MySQL底层知识
主要要从张架构图开始谈起
MySQL架构
记住!**增删查改都不是直接对磁盘或者硬盘操作!**而是先会对MySQL的buffer pool进行操作,而这个是在存储引擎层面的,而不是中间查询缓存的过程!默认buffer pool是128M
![](https://i-blog.csdnimg.cn/blog_migrate/8b6008baa17002f59f289fa070423ded.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8ebc192182bd06ea9d61b6b2eb506a4b.png)
页
buffer pool是存放在内存当中的,主要是存储‘页’,这个页里面是磁盘里面映射的数据。里面既有双向链表,也有单向链表;一页是16KB
![页](https://i-blog.csdnimg.cn/blog_migrate/a4b1295e9329f4b8cf4a16466383b8f0.jpeg)
里面页的连接主要是双向链表,而页里面的数据就是单向链表,而页里面的数据并未是固定的,有可能是叶子节点,也有可能是非叶子节点。但总之里面存储的是数据。
![clipboard.png](https://i-blog.csdnimg.cn/blog_migrate/25c396d6c3353f9fd26b0cb2ed9af5a5.png)
![clipboard.png](https://i-blog.csdnimg.cn/blog_migrate/e9e6eb3ce3941538e23e6dc02224be47.png)
查询
当查询来的时候,会优先查询buffer pool里面的数据,假如里面没有,就会从磁盘中的页复制到buffer pool当中,进而返回查询结果。
但是!一旦有数据更改,将脏页持久化之后,那么那页就会清空,这样会导致碎片化,难以找到空闲页将磁盘的数据复制到buffer pool中,所以有一个链表来完成这个工作——free链表
free链表:主要是记录空闲的页,然后磁盘需要复制页过去的时候,直接对这个链表进行遍历就行了,节省时间;它主要是由一个头节点和空闲页节点(主要是记录地址指针)构成,头节点主要是记录相关的链表数据如,链表长度,链表节点之类的。每当有空闲页产生时,就会插入到链表的后面
当buffer pool里面满了怎么办?
这是也有个链表用于淘汰页,使用最近最少使用(lru链表)淘汰策略,它的结构和之前的链表很像,主要逻辑是当有页被查询到的时候就会将那页插入到头指针后面,如果满了,就淘汰最后的页。
但是如果出现了select * 这种情况怎么办?
该链表为了应对这种情况,将该链表分成两个部分,一个部分用于作为热数据区域(5/8),一个部分作为冷数据区域(3/8),而且会设置一个查询时间节点(默认好像是1秒),当时间短于这个时间不会将了冷数据区域的数据插入到热数据区中,因为select *查询这些页的时候时间都会小于这个时间;大于这个时间就会插入过去;
修改
修改删除则是和上面一致先会去查询,然后对页进行修改。当事务提交时,会将里面修改过的页(脏页)进行持久化。因为读取会直接先从buffer pool读取,就会直接读到脏页,这也就是脏读的来源!
持久化
MySQL持久化,分为页数据的持久化和日志持久化
页数据持久化后台会有线程定时对页数据进行持久化操作,线程通过遍历脏页进行持久化,而这些脏页都会记录到一个链表当中,叫做flash链表,每当有数据进行更新时,就会把该页的节点进行记录插入到flash链表中
flash有一个头节点,用于记录链表中的数据,例如链表长度,链表节点之类。插入的时候会插入到这个头节点之后,线程就是通过遍历这个链表将脏页持久化
日志持久化每当有修改操作产生时,就会有俩个日志产生,一个是undo log,另一个是redo log。undo log主要是记录修改相反的数据,用于回滚。redo log主要是记录修改后的数据,用于持久化。
这俩日志都不是直接写入到日志文件里面的,而是先写入log buffer(日志缓存,在内存中),然后当事务提交之后再写入日志文件。redo log持久化也是有三种方式!
![mysql架构](https://i-blog.csdnimg.cn/blog_migrate/b64d38d791f96c100511f851592a3d4b.jpeg)
第一种:事务提交后并不会马上持久化到日志文件当中,而是交给后台线程去持久化。如果中间MySQL崩了,那就数据没了。id=0
第二种:事务提交后就马上持久化到日志文件当中。id=1(默认)
第三种:事务提交后写入操作系统缓存,让操作系统后台去持久化。只要操作系统不崩,MySQL崩了也可以继续持久化。id=2
![mysql架构2](https://i-blog.csdnimg.cn/blog_migrate/92fa5ee9826ec2dc58a896108212b678.jpeg)
原子性
原子性的实现主要是靠undo log,当事务需要回滚是,主要是靠undo log来回滚数据。
undo log主要是记录更新语句相反的记录,比如我增加了一条数据,undo log就记录删除一条数据。
而且和MVCC密切相关,读已提交和可可重复读就依靠undo log+快照读实现的,解决的了读写冲突和写写冲突
该文章的大致脑图