这里有新鲜出炉的 Mysql 教程,程序狗速度看过来!
MySQL 是一个开放源码的小型关联式数据库管理系统,开发者为瑞典 MySQL AB 公司。MySQL 被广泛地应用在 Internet 上的中小型网站中。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了 MySQL 作为网站数据库。
下面小编就为大家带来一篇 InnoDb 体系架构和特性详解 (Innodb 存储引擎读书笔记总结)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
后台线程
•Master Thread
核心后台线程,主要负责将缓冲池的数据异步刷新到磁盘。例如脏页的刷新,插入缓冲的合并,undo 页的回收等。
每秒一次的操作:
1. 日志缓冲刷新到磁盘,即使该事务还没有提交。该操作总是会发生,这个就是为了再大的事务,提交时间都很短。
2. 当 IO 压力很小时(1s 内发生的 IO 次数小于 5% innodb_io_capacity)合并 5% innodb_io_capacity 的插入缓冲。
3. 当脏页比例大于 innodb_max_dirty_pages_cnt, 刷新 innodb_io_capacity 个缓冲池中的脏页到磁盘。否则如果 innodb_adaptive_flush 开启,则根据 buf_flush_get_desired_flush_rate 来选择合适刷新脏页数量进行刷新。
每 10 秒一次的操作:
1. 如果过去 10S 内 IO 操作小于 innodb_io_capacity, 刷新 innodb_io_capacity 个缓冲池中的脏页到磁盘。
2. 合并 5% innodb_io_capacity 个插入缓冲。
3. 将日志缓冲刷新到磁盘。
4. 删除无用的 undo 页。
5. 如果缓冲池中脏页比例超过 70%,再次刷新 innodb_io_capacity 个脏页到磁盘。否则刷新 10% innodb_io_capacity 个脏页。
background loop(数据库空闲或者数据库关闭时):
1. 删除无用的 undo 页。
2. 合并 innodb_io_capacity 个插入缓冲。
flush loop(数据库空闲):
1. 刷新 innodb_io_capacity 个脏页
•IO Thread
Innodb 存储引擎大量使用了 AIO, IO Thread 主要负责 IO 请求的回调。 可使用 innodb_read_io_threads 和 innodb_write_io_threads 参数列表调整。
•Purge Thread
事务提交后。该事务相关的 undolog 可能不再需要。Purge Thread 就是用来回收不需要的 undo 页的。
•PageCleaner Thread
负责脏页的刷新操作。减轻 master thread 的工作以及对于用户查询线程的阻塞。
内存缓冲池
对于数据库中页的修改操作,首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上。这就意味着不是每次缓冲池中的页修改时触发刷新回磁盘,而是通过 checkpoint 技术刷新回磁盘。缓冲池的大小配置可通过 innodb_buffer_pool_size 来设置。
缓冲池的数据页类型有:数据页,索引页,undo 页,插入缓冲,自适应哈希索引,innodb 存储的锁信息,字典信息。
现在 innodb 存储引擎允许多个缓冲池实例。这样通过 hash 到不同缓冲池实例来减少锁的竞争。该参数可以通过 innodb_buffer_pool_instance.
缓冲池是一个很大的内存区域,数据库通过 LRU 算法来进行管理。但是因为考虑到全表扫描的操作。因此没有采用朴素的 LRU 算法。LRU 列表中加入的 midpoint 位置。新读取到的页,并不是直接放到 lru 列表的首部,而是 midpoint 位置。默认情况下,在 lru 列表长度的 5/8 处。由参数 innodb_old_blocks_pct 控制。
插入缓冲
对于非聚集索引的插入和更新操作,Innodb 存储引擎并不是直接插入到索引页中,而是的 Insert Buffer。然后再以一定的频率进行 insertbuffer 和辅助索引叶子节点的 merge。着通常将多个随机插入合并到一个操作中。大大提高了非聚集索引插入的性能。
Innodb 使用 insertbuffer 条件:
• 索引是非聚集索引
• 索引不是 unique 的 (如果是 unique, 则又需查找索引来保证 unique)
Insert Buffer 内部实现
Insert Buffer 的数据结构是一棵 B + 树。 Mysql 4.1 后,全局只有一棵 B + 树,负责对所有表的辅助索引进行 insert Buffer. 并且,这棵树存放在共享表空间里,默认情况下即 ibdata1。因此,如果仅通过独立表空间 ibd 文件恢复表中数据时,可能会导致失败。还需要通过 insert buffer 数据恢复表上的辅助索引。
Insert Buffer 的非叶节点存放的是查询 key, 构造如 space(4 字节) + marker(1 字节) + offset(4 字节)。space 表示记录所在表的表空间 ID,offset 表示页的偏移量。marker 用来兼容老版本。
Insert Buffer 叶子几点构造如 space + marker + offset + metadata + records。 space, marker, offset 和前述意义相同。 metadata 里的 IBUF_REC_OFFSET_COUNT 保存了两个字节的整数,用来排序记录进入 Insert Buffer 的顺序。通过这个顺序回访呢个得到记录的正确值。从 Insert Buffer 叶子节点的第 5 列开始,才是实际插入的各个记录。
启用 Insert Buffer 索引后,辅助索引页的记录可能被插入到 Insert Buffer B + 树中。为了保证每次合并插入缓冲区成功, 必须要有一块地方能标记每个辅助索引页的可用空间。 Insert Buffer 采用一个特殊的页来标记,该页的类型为 Insert Buffer Bitmap。每个 Insert Buffer Bitmap 页用来追踪 16384 个页,也就是 256 个区。每个 Insert Buffer Bitmap 页都在 16384 个页的第二个页。每个辅助索引页在 Bit map 中占用 4 个字节,这里面主要用于表示辅助索引页的可用数量。
合并插入缓冲
Insert Buffer 中的记录在以下情况下合并到真正的辅助索引中:
• 辅助索引页被读到缓冲池中;
• Insert Buffer Bitmap 页追踪到该辅助索引页已无可用空间时;
• Master Thread 调度时;
这样子,对辅助索引页的多次记录操作通过一次操作合并到了原有的辅助索引页中,从而提高性能。
两次写(Double Write)
InsertBuffer 给 Innodb 存储引擎带来了性能的提升,而两次写带给 Innodb 存储引擎的是数据页的可靠性。
可能会有疑问,如果发生写失败,那么不是可以通过重做日志进行恢复的吗?这的确是一个办法,但是必须知道,重做日志记录的是页的物理操作,如偏移量 800, 写'aaa'记录。但是,如果这个页已经损坏了,对其进行重做是没有意义的。这意味着,在修改页前,必须有一个正确的页的副本存在,当写入失效发生时,先通过页的副本还原该页,再进行重做,这就是 double write。
Double write 由两部分组成,一部分是内存中的 double write buffer。 另一部分是在物理磁盘上的共享表空间中的连续 128 个页,大小和内存中(2M)一致。对缓冲池中的页进行刷新时,并不直接写磁盘,而是 memcpy 到 double write buffer. 之后通过 double write buffer 分两次,每次顺序写入共享表空间 1M 数据,然后马上调用 fsync 同步磁盘。这个写入因为共享表空间的 double write 页是连续的,因此开销不是很大。而完成 double write 页的写入后,再将 double write buffer 中的页写入各个表空间则是离散的写入。
如果操作系统在将页写入磁盘的过程中发生了崩溃。那么恢复时则可以从共享表空间中 double write buffer 页找到该页的副本。将其复制到表空间再应用重做日志。
自适应 HASH 索引
Innodb 存储引擎会监控对表上各索引页的查询,如果观察到建立 hash 索引可以带来速度的提升。则建立 hash 索引,称之为自适应 hash 索引(AHI).
AHI 有一个要求,即对这个页的连续访问模式必须是一样的. 例如(a, b) 这样的联合索引,启访问模式可以使:
WHERE a = xxx
WHERE a = xxx and b = yyy
访问模式一样就是说查询的条件一样。如果交替执行上述的查询操作。则不会建立 AHI。
另外,AHI 还要求以同一个模式访问了 100 次,页通过该模式访问了 N 次,其中 N = 页中记录 * 1/16
刷新邻近页
当刷新一个脏页时,Innodb 存储引擎会通过检测该页所在区的所有页,如果是脏页,会一起进行刷新。
异步 IO
Innodb 采用异步 IO 的方式来处理磁盘操作。
Check Point 技术
为了避免数据丢失的问题,事物数据库系统一般都采用了 write ahead log 策略。即事物提交时,先写重做日志,再修改页。
但是重做日志不可能无限增大,缓冲值(未刷新到磁盘的脏页)也不可能无限大。即便真可以无限大,数据库宕机后恢复时间也会很长。所以就需要 Check Point 技术,该技术可以解决:
• 缩短数据库恢复的时间;
• 缓冲池不够用时,可以将脏页刷新到磁盘;
• 重做日志不可用时(重做日志都是循环利用的),刷新脏页到磁盘;
数据库宕机后重启时,不需要重做所有的日志了。因为 Check Point 之前的页都已经刷新到磁盘,数据库只需对 Check Point 后的重做日志进行恢复即可。从而大大缩短恢复时间。
对于 Innodb 而言,其实通过 LSN (Log Sequence Number) 来比较版本的。 LSN 是一个 8 字节的数字。 每个页有 LSN, 重做日志有 LSN, CheckPoint 也有 LSN。可以通过下述命令观察到
- mysql > show engine innodb status\G;
- .............
- Log sequence number 92561351052
- Log flushed up to 92561351052
- Last checkpoint at 92561351052
以上这篇 InnoDb 体系架构和特性详解 (Innodb 存储引擎读书笔记总结) 就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持 PHPERZ。
来源: http://www.phperz.com/article/17/0618/332631.html