MySQL 之 InnoDB 存储结构 | 京东物流技术团队
1 InnoDB 存储引擎
InnoDB 存储引擎最早由 Innobase Oy 公司开发(属第三方存储引擎)。从 MySQL 5.5 版本开始作为表的默认存储引擎。该存储引擎是第一个完整支持 ACID 事务的 MySQL 存储引擎,特点是行锁设计、支持 MVCC、支持外键、提供一致性非锁定读,非常适合 OLTP 场景的应用使用。目前也是应用最广泛的存储引擎。
InnoDB 存储引擎架构包含内存结构和磁盘结构两大部分,总体架构图如下:
8.0 版本:
5.5 版本:
2 InnoDB 存储结构
2.1 磁盘结构
2.1.1 表空间 Tablespaces
InnoDB 存储引擎的逻辑存储结构是将所有的数据都被逻辑地放在了一个空间中,这个空间中的文件就是实际存在的物理文件(.ibd 文件),即表空间。默认情况下,一个数据库表占用一个表空间,表空间可以看做是 InnoDB 存储引擎逻辑结构的最高层,所以的数据都存放在表空间中,例如:表对应的数据、索引、insert buffer bitmap undo 信息、insert buffer 索引页、double write buffer files 等都是放在共享表空间中的。
表空间分为系统表空间(ibdata1 文件)(共享表空间)、临时表空间、常规表空间、Undo 表空间和 file-per-table 表空间(独立表空间)。系统表空间又包括双写缓冲区(Doublewrite buffer)、Change Buffer 等
1.系统表空间 System Tablespace
系统表空间可以对应文件系统上一个或多个实际的文件,默认情况下, InnoDB 会在数据目录下创建一个名为.ibdata1,大小为 12M 的文件,这个文件就是对应的系统表空间在文件系统上的表示。这个文件是可以自扩展的,当不够用的时候它会自己增加文件大小。需要注意的一点是,在一个 MySQL 服务器中,系统表空间只有一份。从 MySQL5.5.7 到 MySQL5.6.6 之间的各个版本中,我们表中的数据都会被默认存储到这个系统表空间。
2.独立表空间
在 MySQL5.6.6 以及之后的版本中, InnoDB 并不会默认的把各个表的数据存储到系统表空间中,而是为每一个表建立一个独立表空间,也就是说我们创建了多少个表,就有多少个独立表空间。使用独立表空间来存储表数据的话,会在该表所属数据库对应的子目录下创建一个表示该独立表空间的文件,文件名和表名相同,只不过添加了一个.ibd 的扩展名而已。
独立表空间只是存放数据、索引和插入缓冲 Bitmap 页,其他类的数据如回滚(undo)信息、插入缓冲索引页、系统事务信息、二次写缓冲等还是存放在原来的系统表空间。
3.其他类型的表空间
随着 MySQL 的发展,除了上述两种表空间之外,现在还新提出了一些不同类型的表空间,比如通用表空间 (general tablespace)、undo 表空间(undo tablespace)、临时表空间(temporary tablespace)等
4.表空间结构
表空间又由段(segment)、区( extent)、页(page)组成,页是 InnoDB 磁盘管理的最小单位。在我们执行 sql 时,不论是查询还是修改,mysql 总会把数据从磁盘读取内内存中,而且在读取数据时,不会单独加在一条数据,而是直接加载数据所在的数据页到内存中。表空间本质上就是一个存放各种页的页面池。
「页」是 InnoDB 管理存储空间的基本单位,也是内存和磁盘交互的基本单位。也就是说,哪怕你需要 1 字节的数据,InnoDB 也会读取整个页的数据,InnoDB 有很多类型的页,它们的用处也各不相同。比如:有存放 undo 日志的页、有存放 INODE 信息的页、有存放 Change Buffer 信息的页、存放用户记录数据的页(索引页)等等。
InnoDB 默认的页大小是 16KB,在初始化表空间之前可以在配置文件中进行配置,一旦数据库初始化完成就不可再变更了。
2.1.2 重写日志 redo log 文件
redo log 记录数据库的变更,数据库崩溃后,会从 redo log 获取事务信息,进行系统恢复。redo log 在磁盘上表现为 ib_logfile0 和 ib_logfile1 两个文件。MySQL 会在事务的提交前将 redo 日志刷新回磁盘。
在同一时间提交的事务,会采用组提交(group commit)的方式一次性刷新回磁盘。从而避免一个事务刷新一次磁盘,提高性能。
2.1.3 Double Write Files 双写缓冲文件
double write 是保障 InnoDB 存储引擎操作数据页的可靠性。double write 分为两部分组成,一部分在内存中的 double write buffer, 大小为 2MB,另一部分是物理磁盘上共享表空间中连续的 128 个数据页,即 2 个区大小(同样是 2MB)。
2.2 内存结构
InnoDB 存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理,因此可将其视为基于磁盘的数据库系统(Disk-base Database)。在数据库中 CPU 速度与磁盘速度是有很大差距的,基于磁盘的数据库系统通常使用缓冲池技术来提高数据库的整体性能。结构如图所示:
2.1.1 缓存池 Buffer Pool
Buffer Pool 是 InnoDB 内存中的一块占比较大的区域,通过内存的速度来弥补磁盘速度慢对数据库性能的影响。在数据库中进行读取页的操作,首先将从磁盘读到的页放在缓冲池中,这个过程称为将页”FIX”在缓冲池中,下次再读到相同的页时,首先判断该页是否在缓冲池中,若在缓冲池中,直接读取该页,否则读取磁盘上的页。
对于数据库中的页的修改操作,首先修改在缓冲池中的页,然后再以一定频率刷新到磁盘上,这里需要注意的是,页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过一种称为 Checkpoint 的机制刷新回磁盘。
缓存区缓存的数据页类型有:索引页,数据页,undo 页,插入缓冲(change buffer),自适应哈希索引(adaptive hash index),InnoDB 存储锁信息(lock info),数据字典信息(data dictionary)。数据页和索引页占据了缓冲池很大部分。
InnoDB1.0.x 版本开始,允许有多个缓冲池实例,每个页根据哈希值平均分配到不同缓冲池的实例中,这样可以减少数据库内部资源竞争,增加数据库的并发处理能力。
整个 Buffer Pool 的说明用一张图来概括如下:
1.LRU List,Free List 和 Flush List——管理 InnoDB 内存区域
为了缓存管理的效率,缓冲池被实现为页链表,采用三个链表维护内存页,而内存页也因此对应 3 种状态: Free 尚未使用; Clean 已使用但未修改; Dirty(脏页)已修改;Free 页只位于 Free List,而 Clean 和 Dirty 页同时位于 LRU List,Dirty 页只存在于 Flush List;
1)LRU List:
数据库中的缓冲池是通过 LRU(Latest Recent Used,最近最少使用)算法来进行管理的。即最频繁使用的页在 LRU 列表的前端,而最少使用的页在 LRU 列表的尾端。当缓冲池不能存放新读取到的页时,将首先释放 LRU 列表中尾端的页。
在 InnoDB 存储引擎中,缓冲池中页的大小默认为 16KB,同样使用 LRU 算法对缓冲池进行管理。稍有不同的是 InnoDB 存储引擎对传统的 LRU 算法做了一些优化。在 InnoDB 的存储引擎中,LRU 列表中还加入了 midpoint 位置。新读取到的页,虽然是最新访问的页,但并不是直接放入到 LRU 列表的首部,而是放入到 LRU 列表的 midpoint 位置。这个算法在 InnoDB 存储引擎下称为 midpoint insertion strategy。在默认配置下,该位置在 LRU 列表长度的 5/8 处。
参数 innodb_old_blocks_pct 默认值为 37,表示新读取的页插入到 LRU 列表尾端的 37%的位置(差不多 3/8 的位置)。在 InnoDB 存储引擎中,把 midpoint 之后的列表称为 old 列表,之前的列表称为 new 列表。可以简单地理解为 new 列表中的页都是最为活跃的热点数据
那为什么不采用朴素的 LRU 算法,直接将读取的页放入到 LRU 列表的首部呢?
这是因为若直接将读取到的页放入到 LRU 的首部,那么某些 SQL 操作可能会使缓冲池中的页被刷新出,从而影响缓冲池的效率。常见的这类操作为索引或数据的扫描操作。这类操作需要访问表中的许多页,甚至是全部的页,而这些页通常来说又仅在这次查询操作中需要,并不是活跃的热点数据。如果页被放入 LRU 列表的首部,那么非常可能将所需要的热点数据页从 LRU 列表中移除,而在下一次需要读取该页时,InnoDB 存储引擎需要再次访问磁盘。
解决热点数据被移除 LRU 列表
InnoDB 存储引擎引入了另一个参数来进一步管理 LRU 列表,这个参数是 innodb_old_blocks_time,用于表示页读取到 mid 位置后需要等待多久才会被加入到 LRU 列表的热端,通过这个方法尽可能使 LRU 列表中热点数据不被刷出。
当有新的数据从磁盘查询到内存时,会写入到 old sub list 的头部,当此数据再次被查询的时候,即在 old sublist 中命中之后,才会放入 new sublist 的头部。当页从 LRU 列表的 old 部分加入到 new 部分时,称此时发生的操作为 page made young;如果因为 innodb_old_blocks_time 的设置导致页没有从 old 部分移动到 new 部分的操作,称为 page not made young。
通过命令 SHOW ENGINE INNODB STATUS 可以观察到如下内容:
页压缩功能
InnoDB 存储引擎从 1.0.x 版本开始支持压缩页的功能,即将原本 16KB 的页压缩为 1KB、2KB、4KB 和 8KB。而由于页的大小发生了变化,LRU 列表也有了些许的改变。对于非 16KB 的页,是通过 unzip_LRU 列表进行管理的,LRU 中的页包含了 unzip_LRU 列表中的页。
对于压缩页的表,每个表的压缩比率可能各不相同。可能存在有的表页大小为 8KB,有的表页大小为 2KB 的情况。unzip_LRU 是怎样从缓冲池中分配内存的呢?
首先,在 unzip_LRU 列表中对不同压缩页大小的页进行分别管理。其次,通过伙伴算法进行内存的分配。例如对需要从缓冲池中申请页为 4KB 的大小,其过程如下:
检查 4KB 的 unzip_LRU 列表,检查是否有可用的空闲页;
若有,则直接使用;
否则,检查 8KB 的 unzip_LRU 列表;
若能够得到空闲页,将页分成 2 个 4KB 页,存放到 4KB 的 unzip_LRU 列表;
若不能得到空闲页,从 LRU 列表中申请一个 16KB 的页,将页分为 1 个 8KB 的页、2 个 4KB 的页,分别存放到对应的 unzip_LRU 列表中。
2)Free List:
free list 定义是当前没有被使用的内存页,也就是空闲的内存页,当执行查询操作时,如果页已经在 buffer pool 中了,则查询到直接返回,如果没有在 buffer pool,并且 free list 不为空,则会从磁盘中查询对应的数据,放入 free list 的某一页中,并且把这页从 free list 中移除,放入 LRU 队列中。Flush List 中的脏页在执行了刷盘操作后会将空间还给 Free List,通过这种方式可以解决空间碎片化
LRU 列表用来管理已经读取的页,但当数据库刚启动时,LRU 列表是空的,即没有任何的页。这时页都存放在 Free 列表中。当需要从缓冲池中分页时,首先从 Free 列表中查找是否有可用的空闲页,若有则将该页从 Free 列表中删除,放入到 LRU 列表中。否则,根据 LRU 算法,淘汰 LRU 列表末尾的页,将该内存空间分配给新的页。
从上面可以看出 【SHOW ENGINE INNODB STATUS】 :
Free buffers 表示当前 Free 列表中页的数量,Database pages 表示 LRU 列表中页的数量。可能的情况是 Free buffers 与 Database pages 的数量之和不等于 Buffer pool size。因为缓冲池中的页还可能会被分配给自适应哈希索引、Lock 信息、Change Buffer 等页,而这部分页不需要 LRU 算法进行维护,因此不存在于 LRU 列表中。
pages made young 显示了 LRU 列表中页移动到前端的次数,youngs/s、non-youngs/s 表示每秒这两类操作的次数。
这里还有一个重要的观察变量——Buffer pool hit rate,表示缓冲池的命中率,通常该值不应该小于 95%。若发生 Buffer pool hit rate 的值小于 95%这种情况,用户需要观察是否是由于全表扫描引起的 LRU 列表被污染的问题。
3)Flush List:
在 LRU 列表中的页被修改后,称该页为脏页(dirty page),即缓冲池中的页和磁盘上的页的数据产生了不一致。这时数据库会通过 CHECKPOINT 机制将脏页刷新回磁盘,而 Flush 列表中的页即为脏页列表。需要注意的是,脏页既存在于 LRU 列表中,也存在于 Flush 列表中。LRU 列表用来管理缓冲池中页的可用性,Flush 列表用来管理将页刷新回磁盘,二者互不影响。
Flush List 中的脏页在执行了刷盘操作后会将空间还给 Free List。
同 LRU 列表一样,Flush 列表也可以通过命令 SHOW ENGINE INNODB STATUS 来查看,前面例子中 Modified db pages 就显示了脏页的数量。
2.Checkpoint 技术
数据库在发生增删查改操作的时候,都是先在 buffer pool 中完成的,为了提高事物操作的效率,buffer pool 中修改之后的数据,并没有立即写入到磁盘,这有可能会导致内存中数据与磁盘中的数据产生不一致的情况。
倘若每次一个页的变化,就将新页的版本刷新到磁盘,那么这个开销是非常大的,若热点数据集中在某几个页中,那么数据库的性能就会变得非常差。同时,如果在从缓冲池将页的的新版本刷新到磁盘时发生了宕机,那么数据就不能恢复了,为了避免这种情况,当前事务数据库系统普遍都采用了 Write Ahead Log 策略,即当事务提交时,先写重做日志,再修改页,当由于发生宕机而导致数据丢失时,可以通过重做日志来完成数据的恢复。这也是事务 ACID 中 D(Durability 持久性)的要求。
checkpoint 的作用:
缩短数据库的恢复时间
缓冲池不够用时,将脏页刷新到磁盘
重做日志不可用时,刷新脏页
checkpoint 的分类
sharp checkpoint:在关闭数据库的时候,将 buffer pool 中的脏页全部刷新到磁盘中。
fuzzy checkpoint:数据库正常运行时,在不同的时机,将部分脏页写入磁盘,进刷新部分脏页到磁盘,也是为了避免一次刷新全部的脏页造成的性能问题。
2.2.2 写缓冲 Change Buffer
在 MySQL5.5 之前,叫插入缓冲(Insert Buffer),只针对 INSERT 做了优化;现在对 DELETE 和 UPDATE 也有效,叫做写缓冲(Change Buffer)。它是一种应用在非唯一普通索引页(non-unique secondary index page)不在缓冲池中,对页进行了写操作,并不会立刻将磁盘页加载到缓冲池,而仅仅记录缓冲变更(Buffer Changes),等未来数据被读取时,再将数据合并(Merge)恢复到缓冲池中的技术。写缓冲的目的是降低写操作的磁盘 IO,提升数据库性能。
数据的修改分为两个情况:
1.当修改的数据页在缓冲池时
上文讲过,通过 LRU、Flush List 的管理,数据库不是直接写入磁盘中,是先将 redo log 写入到磁盘,再通过 checkpoint 机制,将这些“脏数据页”同步地写入磁盘,等于是将这期间发生的 n 次的落盘合并成了一次落盘。因为有 redo log 是落盘的,所以即使数据库崩溃,缓存中的数据页全部丢失,也可以通过 redo log 将这些数据页找回来。
redo log 是数据库用来在崩溃的时候进行数据恢复的日志,redo log 的写入策略可以通过参数控制,并不一定是每一次写操作之后立即落盘 redo log,在部分参数下,redo log 可能是每秒集中写入一次,也有可能采取其他落盘策略,但是无论采用什么方式,redo log 的量都是不会减少的,与数据写入的覆盖性不同,后一条 redo log 是不会覆盖前一条的,而是增量形式的,因此写 redo log 的操作,等同于是对磁盘某一小块区域的顺序 I/O,而不像数据落盘一样的随机 IO 在磁盘里写入,需要磁盘在多个地方移动磁头。所以 redo log 的落盘是 IO 操作当中消耗较少的一种,比数据直接刷回磁盘要优很多。
2.当修改的数据页不在缓冲池时,不用写缓冲至少需要下面的三步:
先把需要的索引页,从磁盘加载到缓冲池,一次磁盘随机读操作;
修改缓冲池中的页,一次内存操作;
写入 redo log ,一次磁盘顺序写操作;
在没有命中缓冲池的时候,至少多产生一次磁盘 IO,对于写多读少的业务场景,性能损耗是很高的
加入写缓冲优化后,流程优化为:
在写缓冲中记录这个操作,一次内存操作;
写入 redo log,一次磁盘顺序写操作;
其性能与这个索引页在缓冲池中,相近。
3.如何保证数据的一致性?
数据库异常奔溃,能够从 redo log 中恢复数据;
写缓冲不只是一个内存结构,它也会被定期刷盘到写缓冲系统表空间;
数据读取时,有另外的流程,将数据合并到缓冲池;
下一次读到该索引页:
载入索引页,缓冲池未命中,这次磁盘 IO 不可避免;
从写缓冲读取相关信息;
恢复索引页,放到缓冲池 LRU 和 Flush 里;(在真正被读取时,才会被加载到缓冲池中)
4.为什么写缓冲优化,仅适用于非唯一普通索引页呢?
InnoDB 里有聚集索引(Clustered Index))和普通索引(Secondary Index)两种。如果索引设置了唯一(Unique)属性,在 进行修改操作 时, InnoDB 必须进行唯一性检查 。也就是说, 索引页即使不在缓冲池,磁盘上的页读取无法避免(否则怎么校验是否唯一!?)
此时就应该直接把相应的页放入缓冲池再进行修改。
5.除了数据页被访问,还有哪些场景会触发刷写缓冲中的数据呢?
有一个后台线程,会认为数据库空闲时;
数据库缓冲池不够用时;
数据库正常关闭时;
redo log 写满时;(几乎不会出现 redo log 写满,此时整个数据库处于无法写入的不可用状态)
6.什么业务场景,适合开启 InnoDB 的写缓冲机制?
数据库大部分是非唯一索引;
业务是写多读少,或者不是写后立刻读取;
2.2.3 自适应散列索引 Adaptive Hash Index
自适应哈希索引用于优化对 BP 数据的查询。InnoDB 存储引擎会监控对二级索引数据的查找,如果观察到建立哈希索引可以带来速度的提升(最近连续被访问三次的数据),则建立哈希索引,自适应哈希索引通过缓冲池的 B+树构造而来,因此建立的速度很快。InnoDB 存储引擎会自动根据访问的频率和模式来为某些页建立哈希索引。(在高负载系统下 AHI 容易产生资源的争用,进而引起一些 bug 导致系统受影响甚至崩溃,故建议关闭该功能)
2.2.4 重做日志缓冲区 rodo Log Buffer
重做日志缓冲区,当在 MySQL 中对 InnoDB 表进行数据更改时,这些更改首先存储在 InnoDB 日志缓冲区的内存中,然后再写入重做日志(redo logs)的 InnoDB 日志磁盘文件中。他让 MySQL 在崩溃的时候具有了恢复数据的能力,即在数据库发生意外的时候,可以进行数据恢复;
日志缓冲区 log buffer 是内存存储区域,用于保存要写入磁盘上的日志文件的数据。日志缓冲区大小由 innodb_log_buffer_size 变量定义,默认大小为 16MB。
日志缓冲区的内容定期刷新到磁盘。较大的日志缓冲区可以运行大型事务,而无需在事务提交之前将重做日志数据写入磁盘。因此,如果有更新,插入或删除许多行的事务,则增加日志缓冲区的大小可以节省磁盘 I/O。
这里还涉及到一个参数 innodb_flush_log_at_trx_commit :控制如何将日志缓冲区的内容写入并刷新到磁盘,默认为 1,不建议修改
参数为 0 时,表示事务 commit 不立即把 redo log buffer 里的数据刷入磁盘文件的,而是依靠 InnoDB 的主线程每秒(此时间由参数 innodb_flush_log_at_timeout 控制,默认 1s)执行一次刷新到磁盘。此时可能你提交事务了,结果 mysql 宕机了,然后此时内存里的数据全部丢失。
参数为 1 时,表示事务 commit 后立即把 redo log buffer 里的数据写入到 os buffer 中,并立即执行 fsync()操作
参数为 2 时,表示事务 commit 后立即把 redo log buffer 里的数据写入到 os buffer 中,但不立即 fsync()SQL 执行过程
什么是 binlog
binlog 是一个二进制格式的文件,用于记录用户对数据库更新的 SQL 语句信息,默认情况下,binlog 是二进制格式的,不能使用文本工具的命令进行查看,而是使用 mysqlbinlog 解析查看。
binlog 的功能
当数据写入到数据库的时候,会同时把更新的 SQL 语句写入到相应的 binlog 文件里面,同时在使用 mysqldump 进行备份的时候,只是对一段时间的数据进行了全局备份,但是如果备份后发现数据库服务器产生故障,这个时候就要用到 binlog 日志了。
binlog 和 redolog 的区别:
redo log 是在 InnoDB 存储引擎层产生,而 binlog 是 mysql 数据库的上层产生,而且 binlog 是二进制格式的日志,不仅仅针对 InnoDB 存储引擎。
两种日志记录的内容形式不同,MySQL 的 binlog 是逻辑日志,而 InnoDB 存储引擎层面的重做日志是物理日志。
两种日志与记录写入磁盘的时间点不同,二进制日志只在事物提交完成后进行一次写入,而 redo log 的重做日志在事物的进行过程中不断地被写入。
binlog 不是循环使用,在写满或者重启之后,会生成新的 binlog 文件,但是 redo log 是循环使用的。
3 InnoDB 存储特性
写缓冲 Change Buffer
两次写 Double Write
InnoDB 在把 Dirty 脏页写回到表空间之前,在内存中会线拷贝到连续的内存空间 double write buffer 缓冲区,然后再把它们写到一个叫 doublewrite buffer file 的连续磁盘存储区域内,在写 doublewrite buffer file 完成后,InnoDB 才会把 Dirty pages 写到 data file 的适当的位置。如果在写 page 的过程中发生意外崩溃,InnoDB 在稍后的恢复过程中在 doublewrite buffer file 中找到完好的 page 副本用于恢复。
为什么需要双写?
InnoDB 的 Page Size 一般是 16KB,其数据校验也是针对这 16KB 来计算的,将数据写入到磁盘是以 Page 为单位进行操作的。而计算机硬件和操作系统,写文件是以 4KB(512 字节)作为单位的,不能保证 MySQL 数据页面 16KB 的一次性原子写。试想,在某个 Dirty Page flush 的过程中,发生了系统断电(或者 OS 崩溃),16K 的数据只有部分被写到磁盘上,只有一部分写是成功的,这种现象被称为 partial page writes。在出现磁盘崩溃的时候,InnoDB 引擎会从共享表空间中的 doublewrite 找到该页的一个副本,将其复制到表空间文件,再应用重做日志,保障 InnoDB 存储引擎操作数据页的可靠性。
为什么不能使用 redo log 解决 partial page writes?
一旦 partial page writes 发生,那么在 InnoDB 恢复时就很尴尬:redo log 的页大小一般设计为 512 个字节,因此 redo log page 本身不会发生 break page。用 redo log 来解决 partial write 理论上是可行的,不过 innodb 的 redo log 是物理逻辑日志,并不是纯物理日志,因此发生 partial write 后崩溃恢复过程中不能直接应用 redo log ,innodb 发现 break page 后实际上会报错。物理逻辑日志不是完全幂等的,这取决于重做日志类型,对于 INSERT 产生的日志其不是幂等的。
两次写的工作流程
double write 由两部分组成,一部分是 InnoDB 内存中的 double write buffer,大小为 2MB,另一部分是物理磁盘上的 ibdata,系统表空间中大小为 2MB,共 128 个连续的 Page(2*1024/16KB=128),即两个分区(extend)一个段(segment)。其中 120 个页用于批量刷新脏页(如 LRU LIST 刷新与 FLUSH LIST 刷新这两种刷新策略),另外 8 个页用于单页刷新(Single Page Flush)。做区分的原因是批量刷脏是后台线程做的,不影响前台线程。而单页刷新是用户线程发起的,需要尽快的刷脏页并替换出一个空闲页出来。
InnoDB 刷新(写出)缓冲区中的数据页时采用的是一次写多个页的方式:
多个页就可以先顺序写入到 double write buffer,并调用 fsync()保证这些数据被刷新到 double write 磁盘(ibdata)。
然后数据页调用 fsync()被刷新到实际存储位置;
故障恢复时 InnoDB 检查 double write Buffer 与数据页原存储位置的内容,若 double write 页处于页断裂状态,则简单的丢弃;若数据页不一致,则从 double write 页还原。
由于 double write 页落盘与数据页落盘在不同的时间点,不会出现 double write 页和数据页同时发生断裂的情况,因此 doublewrite 技术可以解决页断裂问题,进而保证了重做日志能顺利进行,数据库能恢复到一致的状态。
3.自适应哈希索引 Adaptive Hash Index
4 参考资料
掘金小册《MySQL 是怎样运行的:从根儿上理解 MySQL》学习笔记https://www.jianshu.com/p/3394321c11bf
作者:京东物流 邓钧蔚
来源:京东云开发者社区 自猿其说 Tech
版权声明: 本文为 InfoQ 作者【京东科技开发者】的原创文章。
原文链接:【http://xie.infoq.cn/article/23c925baded2f80df5b0676f8】。文章转载请联系作者。
评论