Mysql技术内幕InnoDB存储引擎——InnoDB存储引擎
特此申明:
前段时间⼯作所以看了《Mysql技术内幕InnoDB存储引擎》,整理的时候除了参考⽹上已有的笔记贴,加上⾃⼰整合的,可能和别⼈有雷同之处。不过⽆所谓啦,写出来⾃⼰看看,需要的朋友参考下,仅此⽽已。
⼀.mysql体系结构和存储引擎
1.1、数据库和实例的区别
数据库:物理操作系统或其他形式⽂件类型的集合。在mysql下数据库⽂件可以是frm,myd,myi,ibd结尾的⽂件。
数据库实例:由数据库后台进程/线程以及⼀个共享内存区组成。数据库实例才是真正⽤来操作数据库⽂件的。
mysql数据库是单进程多线程的程序,与sql server⽐较类似。也就是说,Mysql数据库实例在系统上的表现就是⼀个进程。
1.2、mysql的体系结构
mysql由连接池组件、管理服务和⼯具组件、sql接⼝组建、查询分析器组件、优化器组件、缓存组件、插件是存储引擎、物理⽂件。1.3、mysql存储引擎
1.3.1、innodb存储引擎,特点⽀持外键、⾏锁、⾮锁定读(默认情况下读取不会产⽣锁)、mysql-4.1开始⽀持每个innodb引擎的表单独放到⼀个表空间⾥。innodb通过使⽤MVCC来获取⾼并发性,并且实现sql标准的4种隔离级别,同时使⽤⼀种被称成next-key locking 的策略来避免换读(phantom)现象。除此之外innodb引擎还提供了插⼊缓存(insert buffer)、⼆次写(double write)、⾃适应哈西索引(adaptive hash index)、预读(read ahead)等⾼性能技术。
1.3.2、myisam存储引擎,myisam特点是不⽀持事物,适合olap应⽤,myisam表由MYD和MYI组成。mysql-5.0版本之
前,myisam默认⽀持的表⼤⼩为4G,从mysql-5.0以后,myisam默认⽀持256T的表单数据。myisam只缓存索引数据。
1.3.3、NDB存储引擎,特点是数据放在内存中,mysql-5.1版本开始可以将⾮索引数据放到磁盘上。NDB之前的缺陷是join查询是mysql数据库层完成的,⽽不是存储引擎完成的,复杂的join查询需要巨⼤的⽹络开销,速度很慢。当前mysql cluster7.2版本中已经解决此问题,join查询效率提⾼了70倍。
1.3.4、memeory存储引擎,将数据放到内存中,默认使⽤hash索引,不⽀持text和blob类型,varchara是按照char的⽅式来存储的。mysql数据库使⽤memory存储引擎作为临时表还存储中间结果集(intermediate result),如果中间集结果⼤于memorg表的容量设置,⼜或者中间结果集包含text和blog列类型字段,则mysql会把他们转换到myisam存储引擎表⽽放到磁盘上,会对查询产⽣性能影响。
1.3.5、archive存储引擎,压缩能⼒较强,主要⽤于归档存储。
1.3.6、federated存储引擎,不存储数据,他指向⼀台远程mysql数据库上的表。
1.3.7、maria存储引擎,myisam的后续版本,⽀持缓存数据和索引,⾏锁设计,⽀持mvcc,⽀持事务和⾮事务安全的选项,以及更好的BLOG字符类型的处理性能。
1.3.8、其他存储引擎,sphinx⽤于全⽂索引,infobright⽤于数据仓库。
1.4连接Mysql
1.4.1、TCP/IP:基于⽹络的连接,连接进⾏权限检查。
1.4.2、命名管道和共享内存:Windows系统上同⼀服务器上的两进程可通过命名管道连接,需在配置⽂件中启⽤--enable-named-pipe选项。
1.4.3、Unix套接字:客户端与服务端位于同⼀服务器时才可使⽤,可以在myf中指定-socket=/tmp/mysql.sock,连接时指定./mysql -S/tmp/mysql.sock。
⼆.InnoDB存储引擎
2.2、innodb引擎架构
InnoDB的多个内存块组成了内存池,负责如下⼯作:
1).维护所有进程/线程需要访问的多个内部数据结构。
2).缓存磁盘上的数据,⽅便快速的读取,并且在对磁盘⽂件的数据进⾏修改之前在这⾥缓存。
3).重做⽇志缓存。
后台线程的主要作⽤是负责刷新内存池中的数据,保证缓冲池中的内存缓存是最近的数据,此外、将已经修改的数据⽂件刷新到磁盘⽂件
2.2.1、后台线程
innodb存储引擎后台有7个线程,—–4个IO线程(insert buffer thread,log thread,read thread,write threa
d),1个master thread,⼀个lock监控线程,⼀个错误监控线程。
2.2.2、内存
innodb存储引擎内存由以下三个部分组成:缓冲池(buffer pool),重做⽇志缓存(redo log buffer),额外的内存池(additional memory pool)。可以使⽤ show engine innodb status来查看innodb_buffer_pool的使⽤情况。
innodb_buffer_pool_size:具体看,缓冲池中的数据库类型有:索引页、数据库页、undo页、插⼊缓存页(insert buffer)、⾃适应hash(adaptive hashindex)、innodb存储的锁信息(lock info)、数据字典信息(data dictionary)。
InnoDB⼯作⽅式:将数据⽂件按页(每页16K)读⼊InnoDBbuffer pool,然后按最近最少使⽤算法(LRU)保留缓存数据,最后通过⼀定频率将脏页刷新到⽂件。
2.3、master thread
2.3.1、master thread源码分析
2.3.2、master thread的潜在问题
1、由于硬件的发展,现在的硬件性能已经提⾼了很多,如果innodb每秒最⼤刷新100个脏页,那么效率会很低,为了解决这个问
题,innodb plugin提供了⼀个参数innodb_io_capacity,⽤来表⽰磁盘IO的吞吐量,默认值是200,规则如下:在合并插⼊缓存时,合并插⼊缓存的数量为innodb_io_capacity的5%;在从缓冲区刷新脏页时,啥新脏页的数量为innodb_io_capacity。
2、关于innodb_max_dirty_pages_pct值的争议,如果值过⼤,内存也很⼤或者服务器压⼒很⼤,那么效率很降低,如果设置的值过⼩,那么硬盘的压⼒会增加,建议是在75-80.并且innodb plugin引进了innodb_adaptive_flushng(⾃适应的刷新),该值影响每秒刷新脏页的数量。
2.4、关键特性,为innodb提⾼性能的技术
2.4.1、插⼊缓存
当⼀个表有⾮聚集索引时,对于⾮聚集索引的叶⼦节点的插⼊不是顺序的,这时候需要离散的访问⾮聚集索引页,性能就在这⾥降低了,这是由于b+树的原理导致的。插⼊缓存就是⽤来解决这个问题的。
对于⾮聚集索引的插⼊和更新操作,不是每⼀次都直接插⼊索引页,⽽是先判断插⼊的⾮聚集索引页
是否在缓存中,如果在就直接插⼊,如果不在就放⼊到⼀个插⼊缓冲区中,好似欺骗数据库这个⾮聚集索引已经插⼊到叶⼦节点了。然后再以⼀定的频率插⼊缓存和⾮聚集索引页字节点的合并操作。
插⼊缓存的使⽤需要满⾜以下两个条件(也就是⾮唯⼀的辅助索引):索引是辅助索引;索引不是唯⼀的。
2.4.2、两次写
两次写给innodb带来的是可靠性,主要⽤来解决部分写失败(partial page write)。在应⽤重做⽇之前,我们需要⼀个页的副本,当写⼊失效发⽣时,先通过页的副本来还原该页,再进⾏重做,这就是doublewrite。
doublewrite有两部分组成,⼀部分是内存中的doublewrite buffer,⼤⼩为2M,另外⼀部分就是物理磁盘上的共享表空间中联系的128个页,即两个区,⼤⼩同样为2M。当缓冲池的张也刷新时,并不直接写硬盘,⽽是回通过memcpy函数将脏页先拷贝到内存中的doublewrite buffer,之后通过doublewrite buffer再分两次写,每次写⼊1M到共享表空间的物理磁盘上,然后马上调⽤fsync函数,同步磁盘。
2.4.3、⾃适应哈西索引
由于innodb不⽀持hash索引,但是在某些情况下hash索引的效率很⾼,于是出现了 adaptive hash ind
ex功能,innodb存储引擎会监控对表上索引的查,如果观察到建⽴hash索引可以提⾼性能的时候,则⾃动建⽴hash索引。
2.5、启动、关闭、恢复
innodb_fast_shutdown影响InnoDB表关闭。该参数有0、1、2三个参数。
0 MySQL关闭时 完成所有的full purge和merge insertbuffer操作
1默认值 只将缓冲池内的⼀些脏页刷新⾄磁盘
2将⽇志都写⼊⽇志⽂件不会有任何事务丢失但下次启动时会进⾏recovery
innodb_force_recovery影响整个innodb存储引擎的恢复状况,该值默认为0,表⽰当需要恢复时,需要执⾏所有的恢复操作,当不能进⾏有效恢复时,如数据页发⽣了corruption,mysql数据库可能宕机,并把错误写⼊错误⽇志中。
三.⽂件
3.1参数⽂件
Mysql实例可以不需要参数⽂件,这是所有的参数值取决于编译Mysql时指定的默认值和源代码中指定参数的默认值。其参数⽂件是Mysqlf。
3.1.1、什么是参数
参数是⼀个键/值对。可以使⽤show variables like命令查看,也可以通过information_schema的GLOBAL_VARIABLES视图来查。
3.1.2、参数类型
参数⽂件分为两类:动态参数和静态参数。动态参数意味着你可以在Mysql实例运⾏中进⾏更改;静态参数说明在整个实例⽣命周期内都不得进⾏更改,好像是只读的。对于动态参数,⼜可以分为global和session关键字,表明该参数的修改是基于当前会话还是真格实例的⽣命周期。有些动态参数只能在会话中进⾏修改,如autocommit;有些参数修改完后,在整个实例⽣命周期中都会⽣效,如
binlog_cache_size;⽽有些参数既可以在会话⼜可以在整个实例的⽣命周期内⽣效,如read_buffer_size。
3.2、⽇志⽂件
3.2.1、错误⽇志
错误⽇志对Mysql的启动、运⾏、关闭过程进⾏了记录。出现Mysql不能正常启动时,第⼀个必须查的⽂件应该就是错误⽇志⽂件。使⽤show variables like ‘log_error’来定位⽂件。
3.2.2、慢查询⽇志
慢查询能为SQL语句的优化带来很好的帮助。设定⼀个阀值,将运⾏时间超过该值的所有SQL语句都记录到慢查询⽇志⽂件中。⽤参数long_query_time来设置。另⼀个参数log_queries_not_using_indexes,若运⾏的SQL语句没有使⽤索引,则这条SQL语句会被记录下来。
3.2.3、查询⽇志
mysql存储文档查询⽇志记录了所有对Mysql请求的信息,不论这些请求是否得到正确的执⾏。默认⽂件名为:主机名.log。
3.2.4、⼆进制⽇志
⼆进制记录了对数据库执⾏更改的所有操作,但是不包括SELECT和SHOW操作,还包括了执⾏时间和更改操作时间。可⽤来恢复某些数据,同时也可以⽤来复制同步远程数据库。将binlog_format设置成row,可以⽀持事务隔离级别为READ COMMITTED,以获得更好的并发性。在使⽤MIXED格式下,mysql采⽤STATEMENT格式进⾏⼆进制⽇志⽂件的记录,但是有⼀些情况下会使⽤ROW格式,
可能的情况如下:
1、表的存储引擎为NDB,这个时候DML操作都会以ROW格式记录。
2、使⽤了uuid()、user(),current_user(),found_rows(),row_count(),等不确定函数。
3、使⽤了insert delay语句
4、使⽤了⽤户定于的函数(UDF)
5、使⽤了临时表(temporary table)
注意:针对系统库mysql⾥⾯的表发⽣变化的处理规则如下:
1、 如果采⽤insert,update,delete直接操作表,则⽇志根据binlog_format设定的格式记录。
2、 如果使⽤grant,revoke,set password等DCL语句,那么⽆论如何都会使⽤SBR模式记录。
3、 blockhole引擎不⽀持row格式,ndb引擎不⽀持statement格式。
3.3、套件字⽂件
Unix系统下本地连接Mysql可以采⽤Unix套接字⽅法,需要⼀个套接字⽂件,可以使⽤show variableslike ‘socket’查询。
3.4、pid⽂件和表结构定义⽂件
pid⽂件是实例启动是记录⾃⼰进程ID号的⽂件,表结构定义⽂件是以frm为后缀名的⽂件,还可以⽤来存放视图的定义。
3.5、innodb引擎⽂件
3.5.1、表空间⽂件
默认表空间⽂件为ibdata1⽂件innodb_data_file_path存储数据,innodb_file_per_table可以按表分别产⽣⼀个表空间.db⽂件,但仅存该表的数据索引和插⼊缓冲等信息,其他信息如undo信息,系统事务信息,double write buffer等还是存放在默认表空间(ibdata1或表空间组)⾥。
3.5.2、重做⽇志⽂件
redo log是在实例或者介质失败的时候,⽤来保证数据完整性。每个innodb存储引擎⾄少有⼀个重做⽇志组,每个重做⽇志⽂件组下⾄少⼜2个重做⽇志⽂件,如默认的ib_logfile0、ib_logfile1.为了得到更⾼的可靠性,你可以设置多个重做镜像⽇志组。
因为重做⽇志条⽬先被写到⽇志缓冲中,然后根据⼀定条件刷新到磁盘重做⽇志⽂件中。与redo log相关的就是
innodb_flush_log_at_trx_commit的值,对innodb的性能影响很⼤。他有0,1,2三个值,0代表提交事务时,并不同步写redo log,⽽是等master threas每秒写。1代表commit的时候就将redo log缓存写⼊磁盘,2代表commit的时候将redo log缓存异步的写⼊磁盘。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论