MYSQL
内部模块
连接器(JDBC、ODBC等) =>
[MYSQL 内部
[Connection Pool] (授权、线程复用、连接限制、内存检测等)=>[SQL Interface] (DML、DDL、Views等) [Parser] (Query Translation、Object privilege) [Optimizer] (Access Paths、 统计分析) [Caches & Buffers]=>[Pluggable Storage Engines]
]
=> [File]
一条SQL执行过程
先看看一条查询SQL
- (这里提供一下官方对各存储引擎的文档说明 Mysql存储引擎)
一条 update SQL执行
update的执行 从客户端 => ··· => 执行引擎 是一样的流程,都要先查到这条数据,然后再去更新。要想理解 UPDATE 流程我们先来看看,Innodb的架构模型。
Innodb 架构
上一张 MYSQL 官方InnoDB架构图:
内存结构
这里有个关键点,当我们去查询数据时候会先 拿着我们当前查询的 夜 去 缓冲池 中查询 当前页是否在缓冲池中。如果在,则直接获取。
当是update时,则会直接修改 Buffer中的值。这个时候,缓冲池中的数据就和磁盘中存储的数据不一致了,称为网页。每隔一段时间,Innodb存储引擎就会把脏页数据刷入磁盘。
一般来说当更新一条数据,我们需要将数据给读取到buffer中修改,然后写回磁盘,其中有一次 IO 操作。
图中缓冲池中有一块区域叫做:change buffer。 当更新一个没有 unique index 的数据时,直接将修改的数据放到 change buffer,然后通过 merge 操作完成更新,从而减少了 IO 操作。
- 为什么要没有唯一索引的数据更新时才能这样呢,因为我们更新数据后,可能更新后的数据和已经存在的数据有重复,所以必须从磁盘中把所有数据读出来比对才行。
- 所以当我们的数据是 写多读少 的时候,就可以通过 增加 innodb_change_buffer_max_size 来调整 change buffer在buffer pool 中所占的比例,默认25(即:25%)
问题又来了,merge是如何运作的
有四种情况:
- 有其他访问,访问到了当前页的数据,就会合并到磁盘
- 后台线程定时
- 系统正常shut down之前
- redo log写满的时候
一、redo log是什么
谈到redo,就要谈到innodb的 crash safe,使用 WAL 的方式实现(write Ahead Logging,在写之前先记录日志)
这样就可以在,当数据库崩溃的后,直接从 redo log中恢复数据,保证数据的正确性
- redo log 默认存储在两个文件中 ib_logfile0 ib_logfile1,这两个文件都是固定大小的。为什么需要固定大小?这是因为redo log的顺序读取的特性造成的,必须是连续的存储空间
二、随机读写与顺序读写
看一张图
一般我们的数据都是分散在磁盘上的: 机械硬盘:
- 定位到磁道
- 等待旋转到对应扇区
- 开始读写
固态;
- 直接定位到闪存芯片(这也是为啥固态比机械快)
- 开始读写
而我们去存储时,是通过文件系统与磁盘打交道的,而他们打交道的方式就有两个。随机读写和顺序读写
- 随机读写存储的数据是分布在不同的 块(默认 1block=8扇区=4K)
- 而顺序存储,顾名思义,数据是分布在一串连续的块中,这样读取速度就大大提升了
三、回到我们架构图
看到buffer pool中的Log Buffer,其就是用来写 redo log 之前存在的缓冲区
在这里,redo log具体的执行策略有三种:
- 不用写Log Buffer,只需要每秒写redo log 磁盘数据一次,性能高,但会造成数据 1s 内的一致性问题。适用于强实时性,弱一致性,比如评论区评论
- 写Log Buffer,同时写入磁盘,性能最差,一致性最高。 适用于弱实时性,强一致性,比如支付场景
- 写Log Buffer,同时写到os buffer(其会每秒调用 fsync 将数据刷入磁盘),性能好,安全性也高。这个是实时性适中 一致性适中的,比如订单类。
我们通过innodb_flush_log_at_trx_commit就可以设置执行策略。默认为 1
内存结构小结
- Buffer Pool 用于加速读
- Change Buffer 用于没有非唯一索引的加速写
- Log Buffer 用于加速redo log写
- 自适应Hash索引主要用于加快查询 页。在查询时,Innodb通过监视索引搜索的机制来判断当前查询是否能走Hash索引。比如LIKE运算符和% 通配符就不能走。
硬盘结构
一、System Tablespace
存储在一个叫ibdata1的文件中,其中包含:
- InnoDB Data Dictionary,存储了元数据,比如表结构信息、索引等
- Doublewrite Buffer 当Buffer Pool写入数据页时,不是直接写入到文件,而是先写入到这个区域。这样做的好处