MySQL核心揭秘:InnoDB存储引擎高级特性
一、插入缓存
其实就是插入数据时,不进行立即的插入,即不进行立即的数据落盘,而是先将变更的操作记录到插入缓存中。
具体的:
当对非唯一二级索引进行插入、更新或删除操作时,如果这些索引页不在内存中(即不在缓冲池内),InnoDB不会立即读取这些页到内存以更新索引,而是将这些变更暂时记录在插入缓存中。
然后再进行合并写入:插入缓存会定期地与实际的索引页进行合并。当某个索引页被加载到内存中时(例如由于其他查询访问了该页),InnoDB会检查插入缓存中是否有针对该页的未处理变更,并一次性应用所有相关变更。这种方式减少了磁盘I/O次数,提高了效率。
这能减少随机I/O操作来提升写入性能,特别是在大量插入或更新操作时表现尤为明显
二、两次写
当数据库写物理页时,如果宕机了,那么可能会导致物理页的一致性被破坏。
可能有人会说,重做日志不是可以恢复物理页吗?实际上是的,但是要求是在物理页一致的情况下。
也就是说,如果物理页完全是未写之前的状态,则可以用重做日志恢复。如果物理页已经完全写完了,那么也可以用重做日志恢复。但是如果物理页前面2K写了新的数据,但是后面2K还是旧的数据,则种情况下就无法使用重做日志恢复了。
这里的两次写就是保证了物理页的一致性,使得即使宕机,也可以用重做日志恢复。
在写物理页时,并不是直接写到真正的物理页上去,而是先写到一个临时页上去,临时页写完后,再写物理页。这样一来:
- 如果写临时页时宕机了,物理页还是完全未写之前的状态,可以用重做日志恢复
- 如果写物理页时宕机了,则可以使用临时页来恢复物理页
InnoDB中共享表空间中划了2M的空间,叫做double write,专门存放临时页。
InnoDB还从内存中划出了2M的缓存空间,叫做double write buffer,专门缓存临时页。
每次写物理页时,先写到double write buffer中,然后从double write buffer写到double write上去。最后再从double write buffer写到物理页上去。
三、自适应hash索引
在InnoDB中默认支持的索引结构为 B+ 树,B+ 树索引可以使用到范围查找,同时是按照顺序的方式对数据进行存储,因此很容易对数据进行排序操作,在联合索引中也可以利用部分索引键进行查询 。
而对于Hash索引则只能满足 =,<>,in查询,不能使用范围查询, 而且数据的存储是没有顺序的。
MySQL 默认使用 B+ 树作为索引,因为 B+ 树有着 Hash 索引没有的优点,那么为什么还需要自
适应 Hash 索引呢?
这是因为B+树的查找次数,取决于B+树的高度,在生产环境中,B+树的高度一般为3-4层,故需要3-4次查询。而 Hash 索引在进行数据检索的时候效率非常高,通常只需要 O(1) 的复杂度,也就是一次就可以完成数据的检索。虽然 Hash 索引的使用场景有很多限制,但是优点也很明显。
InnoDB存储引擎会监控对表上各索引页的查询,如果观察到hash索引可以提升速度,则建立hash索引,称之为自适应hash索引(Adaptive Hash Index,AHI)。
四、异步IO
为了提高磁盘的操作性能,在InnoDB存储引擎中使用异步非阻塞AIO的方式来操作磁盘。
与AIO对应的是Sync IO,如果是同步IO操作,则每进行一次IO操作,需要等待此次操作结束后才可以进行接下来的操作。但是如果用户发出的是一条索引扫描的查询,那么这条SQL查询语句可能需要扫描多个索引页,也就是需要进行多次的IO操作。每扫描一个页并等待其完成之后,再进行下一次扫描,这是没有必要的
用户可以在发出一个IO请求后立即再发出另一个IO请求,当全部的IO请求发送完毕后,等待所有的IO操作完成,这就是AIO。
五、刷新临近页
InnoDB提供刷新临近页功能:
当刷新一脏页时,同时检测所在区(extent)的所有页,如果有脏页则一并刷新,好处则是通过AIO特性合并写IO请求,缺点则是有些页不怎么脏也刚好被刷新,而且频繁的更改那些不怎么脏的页又很快变成脏页,造成频繁刷新。