当前位置: 首页 > 科技观察

《MySQL系列》InnoDB

时间:2023-03-12 13:31:55 科技观察

一个存储引擎系统的架构和原理深入分析1.1MySQL架构上图描述ConnectionPool:连接池组件ManagementServices&Utilities:管理服务和工具组件SQLInterface:SQL接口组件Parser:查询分析器组件Optimizer:Optimizer组件Caches&Buffers:缓冲池组件PluggableStorageEngines:存储引擎FileSystem:文件系统1.连接层最上层是一些客户端和链接服务,包括本地sock通信和大部分类似TCP的客户端/服务器端工具/IP通信。主要完成一些类似的连接处理,授权认证,以及相关的安全解决方案。在这一层引入了线程池的概念,为通过认证和安全访问的客户端提供线程。基于SSL的安全链接也可以在该层上实现。服务器还验证它对每个安全访问的客户端所具有的操作权限。2.服务层第二层架构主要完成大部分核心服务功能,如SQL接口、缓存查询、SQL分析和优化,以及一些内置功能的执行。所有跨存储引擎的功能也是在这一层实现的,比如过程、函数等。在这一层,服务器会对查询进行解析,并创建对应的内部解析树,并进行相应的优化,比如确定表查询的顺序,是否使用索引等,最终生成相应的执行操作。如果是select语句,服务器也会查询内部缓存。如果缓存空间足够大,这在解决大量读操作的环境下,可以大大提高系统性能。3.引擎层存储引擎层,存储引擎真正负责MySQL中数据的存储和提取,服务器通过API与存储引擎进行通信。不同的存储引擎有不同的功能,所以我们可以根据自己的需要选择合适的存储引擎。4.存储层数据存储层主要将数据存储在文件系统上,完成与存储引擎的交互。与其他数据库相比,MySQL存储引擎是一种插件式存储引擎架构。将查询处理与其他系统任务以及数据的存储和检索分开。这种架构可以根据业务需要和实际需要选择合适的存储引擎。1.2存储引擎简介1.概述可以针对不同的存储需求选择最优的存储引擎。存储引擎是存储数据、建立索引、更新查询数据等技术的实现。存储引擎是基于表的,而不是基于库的。所以存储引擎也可以称为表类型。2、查看MySQL存储引擎3、MySQL的两种常用引擎MySQL默认支持InnoDB2InnoDB深入分析2.1InnoDB架构1、缓冲池介绍差异非常大。为了尽可能弥补两者在I/O效率上的差异,需要将经常使用的数据加载到缓冲池中,避免每次访问都进行磁盘I/O。在InnoDB的缓冲池中,不仅缓存了索引页和数据页,还包括了undopages、insertcaches、adaptivehashindexes、InnoDBlock信息。当读取数据库中的一个页面时,先将从磁盘读取的页面数据存储在缓冲池中,下次读取相同的页面时,先判断缓冲池中是否存在,如果缓冲池被阻塞,如果存在命中则直接读取数据,未命中则读取磁盘中的页数据。对于数据库中页面的修改操作,首先修改缓冲池中的页面,然后以一定的频率刷新到磁盘,从而保证缓冲池中的数据与数据库中的数据一致磁盘。不需要每次更新页面时都触发将页面从缓冲池刷新回磁盘的操作。出于整体性能考虑,通过checkpoint机制刷新回磁盘。参数在专用服务器上配置,通常多达80%的物理内存分配给缓冲池。参数设置:showvariableslike'innodb_buffer_pool_size';在InnoDB引擎中,允许有多个缓冲池实例,根据页面的哈希值分配给不同的缓冲池实例,从而减少数据库内部的资源竞争,提高并发处理能力。参数配置:vi/etc/my.confinnodb_buffer_pool_size=2684354562。后台线程MasterThread主要负责将缓冲池中的数据异步刷新到磁盘以保持数据一致性,包括刷新脏页、合并插入缓存、undo页回收等。IOThread在InnoDB存储引擎中大量使用了AIO来处理IO请求,可以极大的提升数据库的性能,IOThread主要负责这些IO请求的回调。PurgeThread主要用于恢复事务已经提交的undolog。事务提交后,undolog可能用不到,所以用来恢复。PagerCleanerThread是新引入的线程,用于辅助MasterThread将脏页刷入磁盘,可以减轻MasterThread的工作压力,减少阻塞。3.Filefrmfile这个文件用来保存各个表的元数据信息,主要包括表结构定义。系统表空间系统表空间是InnoDB数据字典、二级写缓冲区、变更缓冲区和撤销日志的存储区。系统表空间可以有一个或多个数据文件。默认情况下,会在数据存储目录下创建一个名为ibdata1的表空间数据文件。文件名可以通过参数innodb_data_file_path指定。file_name:file_size[:autoextend[:max:max_file_size]]在独占表空间innodb中设置参数innodb_file_per_table为1/ON,存储的数据、索引等信息会单独存放在独占表空间中,所以aExclusivetablespacefile(ibd)redolog重做日志,用于恢复被提交事务修改的页操作,保证事务的原子性和持久性。主要问题是提交的事务还没有执行但是数据库已经崩溃了。当数据库恢复时,数据可以完全恢复。InnoDB存储引擎在执行一个操作时,会先将redolog信息放入bufferredologbuffer中,然后根据不同的策略和频率将buffer中的数据flush到redolog中。保存在磁盘中的重做日志名称为ib_logfile0和ib_logfile1。binlog二进制日志,记录表结构的数据变化,包括DDL和DML。其他错误日志、查询日志、慢查询日志等。2.2InnoDB逻辑存储结构1.表空间表空间是InnoDB存储引擎逻辑结构的最高层,大部分数据存在于共享表空间ibdata1中。如果用户启用了参数innodb_file_per_table,那么每张表都会有一个表空间(xxx.ibd),里面存放着表中的数据、索引和insertcacheBitmappages。其他的undolog、insertcacheindexpage、系统事务信息、二级写缓存等数据都在共享表空间中。2.段表空间由各种段组成。公共段包括数据段、索引段和回滚段。InnoDB存储引擎是基于索引组织的,所以数据就是索引,索引就是数据。数据段是B+树的叶子节点,索引段是B+树的非叶子节点。InnoDB中Segment的管理是由引擎自己完成的,不需要人为控制。3、区域是表空间的单位结构,每个区域的大小为1M。默认情况下,InnoDB存储引擎页面大小为16K,即一个区域中有64个连续的页面。4.页页是一个区域的最小单位,页也是InnoDB存储引擎磁盘管理的最小单位。每页的默认大小为16KB。为了保证页面的连续性,InnoDB存储引擎每次从磁盘申请4-5个区域。5.RowsInnoDB存储引擎是面向行的,也就是说数据是按行存储的,每页存储的行记录也是硬定义的,最多允许存储16KB/2-200行。即7992行记录。trx_id:每一条聚簇索引记录发生变化,都会将对应的事务id赋给trx_id隐藏列。roll_pointer:每修改一条聚集索引记录,就会把旧版本写入undolog,然后这个隐藏列就相当于一个指针,通过它可以找到这条记录修改前的信息。2.3检查点1。简介由于日常的DML语句操作,首先操作的是bufferpool,并没有直接写入磁盘,可能会导致内存中的数据和磁盘中的数据不一致,以及磁盘中的数据。数据不一致的页面称为“脏页”。Checkpoint的工作是在一定条件下将内存中的脏页刷新到磁盘中。如果页面数据从缓冲池刷新到磁盘的过程中发生宕机,则数据无法恢复;为了避免这种情况,采用了WriteAheadLog(WAL)策略,即事务提交时,先写入重做日志(redolog),然后修改缓冲池数据页,最后flush到通过检查点磁盘(事务提交会触发检查点)。这样,正在执行的事务因为有日志的存在可以恢复,没有日志的事务还没有执行,不会丢失数据。2.功能A.缩短数据恢复时间当数据库宕机时,数据库不需要重做所有的日志,因为Checkpoint之前的页面已经刷新到磁盘,所以数据库只需要重做之后的日志检查站。恢复时间大大缩短。B、当缓冲池不够时,需要先将脏页数据刷入磁盘;当缓冲池不够时,根据LRU算法溢出最近最少使用的页面。如果页面是脏页,Checkpoint会强制将脏页刷新到磁盘。C.当重做日志不可用时,将脏页刷到磁盘;重做日志的大小是固定的。在目前的InnoDB引擎中,redolog被设计为循环使用,而不是无限增加。不再需要重做日志中可以重用的部分。这部分重做日志即使数据库宕机也不需要,所以可以覆盖掉。如果此时还需要使用redolog,则必须强制执行Checkpoint。,flushbufferpool中的pages至少到磁盘,并且将checkpoint移动到当前redolog位置。writepos表示日志的当前记录位置。当ib_logfile_1写满时,会从ib_logfile_0开头开始记录;checkpoint表示将日志记录的修改写入磁盘,数据写入磁盘。记录被擦除,即writeposition->checkpoint之间的部分是redolog的空部分,用来记录新的记录,checkpoint->writeposition之间的部分是redo的数据修改记录日志放在磁盘上。当writepost赶上checkpoint时,必须先停止记录,将checkpoint前移,为新的log腾出空间。3.分类A.SharpCheckpointSharpCheckpoint发生在数据库关闭时,所有的脏页都被刷新回磁盘。这是默认的工作方式,参数:innodb_fast_shutdown=1。B.FuzzyCheckpoint在InnoDB存储引擎运行时使用FuzzyCheckpoint刷新页面,只刷新部分脏页。2.4InnoDB的主要特点1.插入缓存主键是行的唯一标识符。在应用程序中,行记录的插入顺序一般是按照主键递增的顺序插入。因此,插入聚集索引通常是顺序的,不需要从磁盘随机读取。因此,在这种情况下,插入操作通常会很快完成。但是,不可能每个表上只有一个聚簇索引。更多情况下,一张表上有多个非聚簇二级索引。比如我们还需要根据name字段来查找,name字段是不唯一的。在这种情况下,会生成一个非聚集且非唯一的索引。在执行插入操作时,数据页的存储仍然按照主键id的执行顺序存储,但是对于非聚簇索引,叶子节点的插入不再是顺序的。这时需要离散访问非聚集索引页,此时插入性能变低。不过这并不是name字段上的索引错误,因为B+树的特性决定了非聚集索引插入的离散性。InnoDB存储引擎开创了插入缓冲区的设计。对于非聚集索引的插入或更新操作,不是每次都直接插入索引页,而是先判断插入的非聚集索引页是否在缓冲池中。如果是,直接插入;如果不是,先放到一个insertbuffer中,好像是在欺骗数据库非聚集索引已经插入到叶子节点中,然后在某个时候执行insertbuffer和非聚集索引叶子节点frequency这时候,通常可以将多次插入合并为一次操作(因为在一个索引页中),这样可以大大提高非聚集索引的插入和修改操作的性能。2.二次写入数据库在写入物理页时,如果宕机,可能会破坏物理页的一致性。可能有人会说,重做日志不能恢复物理页面吗?其实是的,但是要求是物理页面一致。换句话说,如果物理页面完全没有被写入,可以用重做日志来恢复。如果物理页面已经完全写入,也可以使用重做日志恢复。但是如果物理页前面2K写入了新数据,而后面2K还是旧数据,那么这种情况下,redologs是无法恢复的。这里的两次写入是为了保证物理页的一致性,这样即使crash了,也可以用redologs来恢复。写物理页时,不是直接写真实的物理页,而是先写一个临时页,写完临时页后再写物理页。这样:A.如果写临时页的时候崩溃了,物理页根本还是写之前的状态,可以用redolog来恢复B.如果写物理页的时候崩溃了page,可以使用临时page来恢复物理page一个page每次写物理page时,先写入doublewritebuffer,然后再从doublewritebuffer写入doublewrite。最后,从双写缓冲区写入物理页。3、InnoDB中自适应哈希索引默认支持的索引结构是B+树。B+树索引可用于范围搜索,按顺序存储数据,便于对数据进行排序。在联合索引中,部分索引键也可以用于查询。对于Hash索引,只能满足=、<>、in查询,不能使用范围查询,数据存储乱序。MySQL默认使用B+树作为索引,因为B+树有Hash索引没有的优点,为什么需要自适应的Hash索引呢?这是因为B+树的搜索次数取决于B+树的高度。在生产环境中,B+树的高度一般为3-4层,所以需要查询3-4次。Hash索引在进行数据检索时效率很高,通常只需要O(1)的复杂度,即一次即可完成数据检索。Hash索引的使用场景虽然有很多局限性,但是优势也很明显。InnoDB存储引擎将监控表上每个索引页的查询。如果观察到哈希索引可以提高速度,就会建立一个哈希索引,称为自适应哈希索引(AdaptiveHashIndex,AHI)。注意,这里的自适应是指不需要手动指定,系统会根据情况自动完成。什么情况下会用到自适应Hash索引呢?如果某个数据被频繁访问,当满足某些条件时,该数据页的地址将存储在哈希表中。这样下次查询的时候就可以直接找到这个页面所在的位置了。值得注意的是,哈希索引只能用于查询中的=,,哈希索引不能用于其他查询类型,如范围匹配。而且,自适应Hash索引只保存热数据(经常使用的数据),而不是全表数据。因此数据量不是很大,所以自适应哈希也存储在缓冲池中,进一步提高了搜索效率。4、异步IO为了提高磁盘的操作性能,InnoDB存储引擎采用异步非阻塞AIO来操作磁盘。与AIO对应的是SyncIO。如果是同步IO操作,每进行一次IO操作,都需要等待操作结束才能进行下一次操作。但是如果用户发出一个索引扫描查询,那么这个SQL查询语句可能需要扫描多个索引页,也就是需要进行多次IO操作。不必扫描每一页并等待它完成后再扫描下一页。用户可以在发送一个IO请求后立即发送另一个IO请求。所有IO请求发送完毕后,等待所有IO操作完成。这是一体机。5.刷新相邻页面InnoDB提供了刷新相邻页面的功能:当刷新一个脏页时,同时检测extent(范围)内的所有页面,如果有脏页则一起刷新。优点是写IO请求通过AIO特性合并缺点是有些页面即使不是很脏也可以刷新,而那些不是很脏的页面频繁变化后会很快变成脏页,导致频繁刷新刷新。对于固态硬盘,可以考虑关闭这个特性(设置innodb_flush_neighbors为0)。2.5InnoDB事务事务可以由一个简单的SQL语句或一组复杂的SQL语句组成。事务是访问和更新数据库中各个数据项的程序执行单元。在事务运行过程中,这组执行单元中的SQL要么全部成功,要么全部失败。1、事务具有以下四个特点(ACID)2、隔离级别并发事务带来的问题:为了解决上面提到的事务并发问题,数??据库提供了一定的事务隔离机制来解决这个问题。数据库的事务隔离越严格,并发带来的副作用越小,但代价越大,因为事务隔离在一定程度上本质上是事务的“序列化”,这与“并发”显然是矛盾的。数据库有四种隔离级别,从低到高,readuncommitted,readcommitted,repeatableread,serializable。这四个层次可以一一解决脏写、脏读、不可重复读、幻读等问题。3.实施1).重做日志重做日志称为重做日志,用于实现事务持久化。日志文件由两部分组成:重做日志缓冲区(redologbuffer)和重做日志文件(redolog),前者在内存中,后者在磁盘中。事务提交后,所有的修改信息都会保存在日志中,用于刷脏页到磁盘出错时的数据恢复。示例:执行事务操作starttransaction;selectbalancefrombankwherename="Tom";--生成redologbalance=8000updatebanksetbalance=balance-2000;--生成redologaccount=2000updatefinancesetaccount=account+2000;commit;进程mysql不会提高性能将每次修改实时同步到磁盘,而是先保存在BufferPool(缓冲池)中,并以此作为缓存。然后使用后台线程将缓冲池刷新到磁盘。在执行刷新、停机或断电时,一些数据可能会丢失。因此引入redolog来记录事务提交成功的修改信息,事务提交时redolog会持久化到磁盘,系统重启后通过读取redolog可以恢复最新的数据.简单来说,redolog用于恢复数据,保证已提交事务的持久化特性;2).undologundolog称为回滚日志,用于记录数据被修改前的信息。他和上面说的redolog里面记录的正好相反。重做日志记录了数据被修改后的信息。undolog主要记录数据的逻辑变化。为了在出错的时候回滚之前的操作,需要把之前的所有操作都记录下来,然后在出错的时候回滚。undolog记录了上一版本事务修改的数据信息,所以如果因为系统错误或者回滚操作而回滚,可以根据事务修改前的信息回滚到未修改前的状态撤消日志。三种存储引擎应用场景在选择存储引擎时,应根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统,也可以根据实际情况选择多个存储引擎进行组合。以下是几种常用存储引擎的使用环境。InnoDB:是Mysql默认的存储引擎,用于事务处理应用,支持外键,行锁。如果应用对事务的完整性要求比较高,要求并发条件下的数据一致性,数据操作除了插入和查询外还包括很多更新和删除操作,那么InnoDB存储引擎是更合适的选择。InnoDB存储引擎除了能有效减少删除和更新带来的锁,还能保证事务的完整提交和回滚。对于电商系统中商品(SPU、SKU、品类、品牌)、订单、用户等信息的存储,InnoDB是最合适的选择。MyISAM:如果应用主要是读和插入操作,很少有更新和删除操作,对事务的完整性和并发性要求不是很高,那么这个存储引擎非常适合选择。对于电商系统,MyISAM是存储系统运行日志、用户评价、足迹等信息的合适选择。