MySQL技术内幕(一)
MySQL技术内幕
2. InnoDB存储引擎
2.1 InnoDB存储引擎概述
特点:行锁设计、支持MVCC、支持外键、提供一致性非锁定读
2.2 InnoDB体系架构

2.2.1 后台线程
InnoDB存储引擎时多线程的模型,因此后台有多个不同的后台线程,负责处理不同的任务。
1. Master Thread
非常核心的后台线程,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括脏页的刷新、合并插入缓冲(INSERT BUFFER)、UNDO页的回收等
2. IO Thread
InnoDB引擎中使用了大量的AIO(Async IO)来处理IO请求,IO Thread的主要工作时负责这些IO请求的回调处理。
4个IO Thread:write、read、insert buffer和log IO Thread。
3. Purge Thread
事务被提交后,其所使用的undolog可能不再需要,因此需要PurgeThread来回收已经使用并分配的undo页。
4. Page Cleaner Thread
作用是将之前版本中脏页的刷新操作都放入到单独的线程中来完成。
2.2.2 内存
1. 缓冲池(Buffer Pool)
- 读取:在数据库中进行读取页的操作,首先将从磁盘读到的页存放在缓冲池中,这个过程称为将页“FIX”在缓冲池中。下一次再读相同的页时,首先判断该页是否在缓冲池中。若在缓冲池中,称该页在缓冲池中被命中,直接读取该页。否则,读取磁盘上的页。
- 修改:对于数据库中页的修改操作,则首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上。这里需要注意的是,页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过一种称为Checkpoint的机制刷新回磁盘。
缓冲池中的数据类型:索引页、数据页、undo页、插入缓冲(insert buffer)、自适应哈希索引(adaptive hash index)、锁信息(lock info)、数据字典信息(data dictionary)。

2. LRU算法及优化
典型的LRU算法是最频繁使用的页在LRU列表的前端,而最少使用的页在LRU列表的尾端。当缓冲池不能存放新读取到的页时,将首先释放LRU列表中尾端的页。
问题:
- 全表扫描:全表扫描的数据量大,需要淘汰的数据页多,在淘汰的过程中极有可能将频繁使用到的数据页给淘汰了,而新数据却是使用频率很低的数据。
- 预读
优化:
- 冷热分离:
- 将LRU链表分为两部分,一部分用来存放冷数据,也就是刚从磁盘读进来的数据,另一部分用来存放热点数据,也就是经常被访问到的数据。
- 当从磁盘读取数据页后,会先将数据页放到LRU链表冷数据区的head,如果这些数据页在1s后再被访问,则这些数据页会被移动到热点数据区的head。
- 淘汰数据页时,从冷数据区的tail开始淘汰。
- 当一个数据页处于热点数据区,且在热点数据区的前1/4区域,那么当访问这个数据页的时候,不需要移动到热点数据区的head部,如果位于热点数据区的后3/4区域,那么当访问这个数据页的时候,会把它移动到热点数据区的head部。
- 支持多个Buffer Pool。
3. Flush列表
在LRU列表中的页被修改后,称该页为脏页(dirty page),即缓冲池中的页和磁盘上的页的数据产生了不一致。这时数据库会通过CHECKPOINT机制将脏页刷新回磁盘,而Flush列表中的页即为脏页列表。需要注意的是,脏页既存在于LRU列表中,也存在于Flush列表中。LRU列表用来管理缓冲池中页的可用性,Flush列表用来管理将页刷新回磁盘,二者互不影响。
4. 重做日志缓冲(redo log buffer)
重做日志在下列三种情况下会将重做日志缓冲中的内容刷新到外部磁盘的重做日志文件中:
- Master Thread每一秒将重做日志缓冲刷新到重做日志文件;
- 每个事务提交时会将重做日志缓冲刷新到重做日志文件;
- 当重做日志缓冲池剩余空间小于1/2时,重做日志缓冲刷新到重做日志文件。
2.3 Checkpoint 技术
脏页:如果一条DML语句,如Update、Delete改变了页中的记录,也就是缓冲池中页的版本比磁盘的新,那么此时页就是脏的。
事务提交时,先写重做日志,再修改页,实现ACID中的D(Durability持久性)。
在InnoDB引擎中,通过LSN(Log Sequence Number)来标记版本,LSN是8字节的数字,单位是字节。
发生Fuzzy Checkpoint的情况:
- Master Thread Checkpoint:Master Thread每秒或每十秒从缓冲池的脏页列表中异步刷新一定比例的页回磁盘;
- FLUSH_LRU_LIST Checkpoint:Page Cleaner线程在LRU列表中空闲页少于某值得时候,会从LRU列表尾端移除一些页,如果这些页中有脏页,那么需要进行Checkpoint;
- Async/Sync Flush Checkpoint:重做日志文件不可用时,Page Cleaner Thread强制刷新一些页回磁盘;
- Dirty Page too Much:缓冲池中脏页比例超过设定值时,强制刷新一些页回磁盘。
2.4 Master Thread
Master Thread:最高优先级,由主循环、后台循环、刷新循环、暂停循环组成,根据数据库状态自动切换循环。
Master Thread 伪代码:
void master_thread() {
goto loop;
loop: // 1. 主循环
for (int i = 0; i< 10; i++) {
Thread.sleep(1000); // 休眠一秒
// 每秒的操作
1.1.1. 刷新日志缓冲到磁盘,即使这个事务还没有提交;
// innodb_io_capacity设置的磁盘IO吞吐量
if (last_one_second_ios < 5% * innodb_io_capacity) {
// 如果当前1秒发生IO次数小于5
1.1.2. 合并插入缓冲(Insert Buffer), 数量:5% * innodb_io_capacity;
}
if (buf_get_modified_ratio_pct > innodb_max_dirty_pages_pct) {
// 如果当前缓冲池中脏页比例大于配置文件中的设定值
1.1.3.1. 刷新至多innodb_io_capacity个脏页到磁盘;
} else if (enable adaptive flush) { // 自适应刷新,通过产生redo日志速度判断
1.1.3.2. 刷新合适量的脏页到磁盘;
}
if (no user activity) {
// 没有用户活动(数据库空闲),则切换到后台循环
1.1.4. goto background loop;
}
}
// 每十秒的操作
if (last_ten_second_ios < innodb_io_capacity) {
1.2.1. 刷新innodb_io_capacity个脏页到磁盘;
}
1.2.2. 合并至多5% * innodb_io_capacity个插入缓冲;
1.2.3. 将日志缓冲刷入到磁盘;
1.2.4. 删除最多20个无用的undo页;
if (buf_get_modified_ratio_pct > 70%) {
1.2.5.1 刷新innodb_io_capacity个脏页到磁盘
} else {
1.2.5.2 刷新10% * innodb_io_capacity脏页到磁盘
}
goto loop;
background loop: // 2. 后台循环
2.1. 删除无用的undo页;
2.2. 合并innodb_io_capacity个插入缓冲;
if (not idle) {
// 跳回主循环
goto loop;
} else {
// 跳到刷新循环
goto flush loop;
}
flush loop: // 3. 刷新循环
3.1. 刷新innodb_io_capacity个脏页到磁盘;
if (buf_get_modified_ratio_pct > innodb_max_dirty_pages_pct) {
// 如果当前缓冲池中脏页比例大于配置文件中的设定值
goto flush loop;
}
goto suspend loop;
suspend loop: // 4. 暂停循环
suspend_thread(); // Master Thread 挂起
waiting event; // 等待事件的发送
goto loop;
}
InnoDB 1.2.x版本的Master Thread
if InnoDB is idel:
srv_master_do_idle_tasks();
else:
srv_master_do_active_tasks();
其中:srv_master_do_idle_tasks()就是之前版本中每10秒的操作,srv_master_do_active_tasks()处理的是之前每秒中的操作。刷新脏页的操作,分离到一个单独的Page Cleaner Thread。
2.5 InnoDB的关键特性
2.5.1 Insert Buffer
对于非聚集且不是唯一索引的插入或者更新操作,不是每一次都直接插入到索引页中,而是先判断插入的非聚集索引页是否在缓冲池中,若在,则直接插入;若不在,则先放到一个Insert Buffer对象中,然后在以一定的频率和情况进行Insert Buffer和辅助索引叶子节点的merge操作。能大大提高对于非聚集索引插入的性能。
Insert Buffer的使用需要满足以下两个条件:
- 索引是辅助索引(secondary index);
- 索引不是唯一(unique)。
Merge Insert Buffer
可能发生在以下几种情况:
- 辅助索引页被读取到缓冲池;
- Insert Buffer Bitmap页追踪到该辅助索引页已无可用空间;
- Master Thread
2.5.2 两次写(double write)
部分写失效(partial page write):
数据库宕机时,缓冲池的某个页只写了一部分到磁盘中,比如16KB的页,只写了前4KB就发生了宕机,这种情况被称为部分写失效。
redo日志记录的是对页的物理操作,如偏移量,因此重做是无意义的。

2.5.3 自适应哈希
数据库自优化,通过B+树页构造哈希索引,提升查询速度。
2.5.4 异步IO
2.5.5 刷新邻接页
MySQL技术内幕(一)的更多相关文章
- Mysql技术内幕(第四版)读书笔记(一)
题记:写代码已经有2年了,学到了很多知识,但是没有一个好习惯去记录,去分享,好多知识点都会忘记,所以从今天开始学着像大牛一样去记录自己经历项目的点点滴滴,先从最近读<Mysql技术内幕>开 ...
- mysql技术内幕InnoDB存储引擎-阅读笔记
mysql技术内幕InnoDB存储引擎这本书断断续续看了近10天左右,应该说作者有比较丰富的开发水平,在源码级别上分析的比较透彻.如果结合高可用mysql和高性能mysql来看或许效果会更好,可惜书太 ...
- MySql技术内幕之MySQL入门(2)
MySql技术内幕之MySQL入门(2) 接上一篇. mysql> source create_member.sql; # 创建member表 Query OK, 0 rows affected ...
- MySql技术内幕之MySQL入门(1)
目录 MySql技术内幕之MySQL入门(1) 安装 关于注释 执行SQL语句 关于命令大小写 创建数据库 查看表的信息 查看更加详细的信息 查看与给定模式相匹配的列 插入数据 利用insert添加行 ...
- 《MySQL技术内幕:InnoDB存储引擎(第2版)》书摘
MySQL技术内幕:InnoDB存储引擎(第2版) 姜承尧 第1章 MySQL体系结构和存储引擎 >> 在上述例子中使用了mysqld_safe命令来启动数据库,当然启动MySQL实例的方 ...
- 《mysql技术内幕 InnoDB存储引擎(第二版)》阅读笔记
一.mysql架构 mysql是一个单进程多线程架构的数据库. 二.存储引擎 InnoDB: 支持事务 行锁 读操作无锁 4种隔离级别,默认为repeatable 自适应hash索引 每张表的存储都是 ...
- Mysql技术内幕——InnoDB存储引擎
Mysql技术内幕——InnoDB存储引擎 http://jingyan.baidu.com/article/fedf07377c493f35ac89770c.html 一.mysql体系结构和存储引 ...
- 《[MySQL技术内幕:SQL编程》读书笔记
<[MySQL技术内幕:SQL编程>读书笔记 2019年3月31日23:12:11 严禁转载!!! <MySQL技术内幕:SQL编程>这本书是我比较喜欢的一位国内作者姜承尧, ...
- 读书笔记-《Mysql技术内幕》
MYSQL 技术内幕 Mysql体系 连接池组件 管理服务和工具 SQL接口 查询分析器 优化器 缓冲 插件式存储引擎 物理文件 存储引擎 InnoDB(默认引擎) 支持事务 行锁设计 多版本并发控制 ...
- Mysql技术内幕之InnoDB锁探究
自7月份换工作以来,期间一直在学习MySQL的相关知识,听了一些视频课,但是一直好奇那些讲师的知识是从哪里学习的.于是想着从书籍中找答案.毕竟一直 看视频也不是办法,不能形成自己的知识.于是想着看书汲 ...
随机推荐
- spoj-SUBSUMS - Subset Sums
SUBSUMS - Subset Sums Given a sequence of N (1 ≤ N ≤ 34) numbers S1, ..., SN (-20,000,000 ≤ Si ≤ 20, ...
- 【LeetCode】99. Recover Binary Search Tree 解题报告(Python)
[LeetCode]99. Recover Binary Search Tree 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/p ...
- Fast Matrix Operations(UVA)11992
UVA 11992 - Fast Matrix Operations 给定一个r*c(r<=20,r*c<=1e6)的矩阵,其元素都是0,现在对其子矩阵进行操作. 1 x1 y1 x2 y ...
- 七、Uniapp+vue+腾讯IM+腾讯音视频开发仿微信的IM聊天APP,支持各类消息收发,音视频通话,附vue实现源码(已开源)-聊天消息项的实现
会话好友列表的实现 1.项目引言 2.腾讯云后台配置TXIM 3.配置项目并实现IM登录 4.会话好友列表的实现 5.聊天输入框的实现 6.聊天界面容器的实现 7.聊天消息项的实现 8.聊天输入框扩展 ...
- CapstoneCS5212|DP to VGA|CS5212设计电路方案
CS5212功能概述 CS5212是一款DisplayPort端口到VGA转换器,它结合了DisplayPort输入接口和模拟RGB DAC输出接口.嵌入式单片机基于工业标准8051核心. CS521 ...
- Java初学者作业——计算大庆路小学的面积练习
返回本章节 返回作业目录 需求说明: 大庆路小学因为装修需要对教室的一侧墙面进行重新粉刷,墙面安装了一面黑板,墙面的长和高以及黑板的长和高. 请编写Java程序计算出需要粉刷的墙面面积.功能要求:输入 ...
- layedit赋值方法(layedit.setContent赋值时报错-ReferenceError: layedit is not defined)
layedit.setContent赋值时报错 - ReferenceError: layedit is not defined 报错代码: 控制台报错信息 解决方法: 步骤: 1)先赋值: 2)在渲 ...
- UTF-8,GBK,ANSI之间的关系和区别
GBK应该是属于ANSI之中的,在ANSI的国际通用集,GBK是专门来解决中文编码的,是双字节的,不论中英文都是双字节,而UTF-8是才用的另外的一种编码方式,对英文是用8位,对中文使用24位,是和A ...
- go语言生成markdown文档工具
虽然有go语言的swagger,但是go版本的swagger对代码的侵入比较大,因此抽空实现了基于GO语言生成markdown文档的工具 开源链接地址: https://github.com/w3li ...
- 初识python: os 模块
偷下懒,直接看代码吧: #!/user/bin env python # author:Simple-Sir # time:2019/8/21 16:38 # os 模块 import os # os ...