一.Mysql架构
我们在终端上调用的 mysql 就是一个 MySQL Client Program, 是一个命令行程序,可以连接 MySQL Sever,执行一些SQL语句. 还有mysqlcheck、mysqldunm等,都是mysql官方提供的. 此外还有Go语言 sql标准库提供的连接函数可以连接到 Mysql Sever
主要做事情的就是Mysql Sever. 在系统中是一个叫mysqld的守护进程(daemon),一般是开机自启
数据库本质上是一些文件的集合,用来储存数据的. 我们一般讲的数据库是 数据库实例, 是用来操作数据库文件的. MySQL数据库实例在系统上表现的就是一个进程,就是mysqld.
1.MySQL Sever 做绝大多数工作,下面是其体系结构图
MySQL的储存引擎是插件式的,是基于表而不是数据库. 因此同一个数据库中可以有使用不同存储引擎的表
存储引擎常用的一般就是InnoDB了
2.InnoDB存储引擎体系架构
后台线程有 Master Thread, IO Thread, Purge Thread 等, 就是做各种事情的,比如将缓冲池的数据刷新到磁盘,处理IO请求.
InnoDB存储引擎是基于磁盘储存的(话说Redis是基于内存存储的?). 由于CPU速度和磁盘速度的巨大差异, InnoDB采用缓冲池技术来提高数据库整体性能
3.InnoDB的逻辑储存结构
- page 的大小默认是16KB.
二.缓冲池(Buffer pool)
1.缓冲池结构
在缓冲池中是对页(Page)进行操作,页是InnoDB磁盘管理的最小单位
一般查询时, 先进行读取页的操作,把磁盘中读到的页放在缓冲池中. 下次再次读取到相同的页时先判断该页是否在缓冲池中,如果在,就直接从缓冲池中读取,称为该页在缓冲池中被命中(hit), 否则,就从磁盘读取.
对页的修改操作,也是先修改缓冲池中的页,然后再以一定的频率刷新到磁盘上(这个就是Master Thread 做的事情了).
可以想象, 缓冲池的容量越大,能缓冲的页就越多,对数据库的读写速度越快,数据库性能越优良. 一般在专用服务器上,缓冲池大小能占内存的80%.
接下来上图
这个图过时了,MySQL5.6的版本(最新是8.0), 这图意思意思就行
缓冲池中的数据页和索引页占很大一部分. 数据页就是储存我们的Record.
图中的那个结构就叫一个缓冲池实例, InnoDB允许有多个缓冲池实例,来缓解并发操作时的资源竞争问题, 从磁盘中读取的页会通过哈希算法平均分配到不同的缓冲池实例中.(这个和缓冲池大小一样都是可以进行设置的)
2. LRU List
- 缓冲池被分为一张张的页(Page)来管理数据. 你可以想像成是一张张连续页组成的列表(Page List). 这些页通过LRU(Latest Recently Used)算法来管理.
下面上图
Old Sublist中的页叫 Old Page, 它被读取后会被移动到New Sublist 的头部,这个过程叫(make young)
New Sublist 中的页叫 New Page, 未被读取的话会往下移动
翻译出来怪怪的,直接贴原文
As the database operates, pages in the buffer pool that are not accessed “age” by moving toward the tail of the list. Pages in both the new and old sublists age as other pages are made new. Pages in the old sublist also age as pages are inserted at the midpoint. Eventually, a page that remains unused reaches the tail of the old sublist and is evicted(被刷出LRU列表).
-
为什么最新读进缓冲池的数据不是直接插在New Sublist的顶部? 因为5/8的数据是热点数据,就是最近或者经常被读取的, 但是SQL的一些扫描操作
需要访问表中的大部分页甚至是全部,就会把之前经常访问的一些热点数据给刷掉,所以从5/8的那个部分插入.
LRU列表管理的是已经被读取的页. 但是数据库刚启动的时候,LRU列表是空的. 这时缓冲池所有的页都放在Free列表中. 当需要从缓冲池中申请页时,先从Free列表中查找是否有空闲的页,有就将该页从Free列表中删除,放到LRU列表中.否则就要淘汰LRU列表末尾的页了.
通过SHOW ENGINE INNODB STATUS 命令可以查看相关的参数
前两个单位是byte, 后面是页,页的默认大小是16KB.
Database pages 就是LRU列表的Page数
对数据的修改也是先缓冲到缓冲池的,被修改过的页叫脏页(Dirty Page), 就是Modified db pages. 通过Checkpoint机制将脏页刷新回磁盘.
young/s 是只Old Pages 平均每秒被读取的总次数, 如果这个值太低的话,可能是Old Sublist 设置的太小了,要把它增大点
Buffer pool hit rate 就是之前讲的命中率, 命中率越高说明数据库性能越好
3.Change Buffer
clustered index(聚合索引),在InnoDB中也叫主键索引(primary key), 就是我们建表的时候指定主键的那个列,其值是唯一的.我们每张表都要有一个主键,表中数据的存储顺序是根据主键的值来的,为了加速涉及到主键的查询.
在用 Where 子句时,如果有对索引列的引用,查询就很快. 但是很多时候我们查询(Insert,Update也要用到查询)不需要用到主键,我们会对其他列建立索引. 其他列不保证数据的唯一性, 这种索引就是叫secondary index(辅助索引) .
前面我们知道缓冲池有数据页还有索引页等. Change Buffer 就是缓冲 涉及对辅助索引页的 INSERT, UPDATE, OR DELETE 操作.
-
辅助索引的值不是唯一的也比较离散,对辅助的索引和删除操作会影响到索引树中其他的索引页,(就比如对一张页的修改可能会牵扯到好几张页,都读入缓冲池的话磁盘I/O开销较大,) 所以设计思路是:
对索引页的修改,先看要被修改页是不是在缓冲池中,如果在就直接写进缓冲池中的索引页,如果不在,就缓冲在Change Buffer中. 当要被修改的索引页被读进缓冲池后,再将Change Buffer中的修改合并到缓冲池中.
SHOW ENGINE INNODB STATUS; 可以查看Change Buffer 状态
我自己测不出变化,数据量少的时候,数据库所有的数据都会被缓冲到缓冲池,change buffer 不起作用.
部分图片来源:
- https://dev.mysql.com/doc/refman/8.0/en/
- <<MySQL技术内幕, InnoDB存储引擎>>