最终MySQL的数据都是放在磁盘文件里的。
那么数据在磁盘文件里是怎么存放的呢?
我们知道数据都是插入一个一个的表里的,而表是个逻辑概念,其实在物理层面,表对应的是表空间这个概念。
即在MySQL磁盘上,表空间就对应着磁盘文件,在磁盘文件里就存放这数据
那这个表空间的磁盘文件里,数据时如何组织的呢?
这个就非常复杂了!可以想象一下,如果把数据直接一行一行的写入一个磁盘文件,当然很简单了。
但是现在要存储的是数据库里如此复杂的数据,它里面是有各种字段类型的,还有索引这个概念。
所以其实在磁盘文件里存放的数据,从最基本的角度来看,就是被拆分为一个一个的数据区(extent)分组,每个extent组中包含256个extern,每个extent里包含64个数据页,每个数据页里包含了一行一行的数据。
在实际存储的时候,在数据行里有很多附加信息。在数据页、数据区里,都有很多特殊的附加信息。各种各样的特殊信息,就可以让我们在磁盘文件里实现B+树索引、事务之类的非常复杂的机制。
当我们在执行CRUD的时候,必须先把磁盘文件的一个数据页加载到内存的buffer pool的一个缓存页里去,然后我们增删查改都是针对缓存页里的数据来执行的。那么假设我们此时要插入一条数据,那么是选择磁盘文件里的哪个数据页加载到缓存页里去呢?
这个时候会先看看是往哪个表里面插入数据,然后根据表找到一个表空间。
找到表空间之后,就可以定位对应的磁盘文件。有了磁盘文件之后,就可以从里面找一个extent组,找一个extent,接着从里面找一个数据页出来。这个数据页可能是空的,也可能是已经放了一些数据行了。
然后就可以把这个数据页从磁盘里完整加载出来,放入buffer pool的缓存页里了。如下图:
从磁盘文件里读取一个数据页,到底是怎样读取的?
磁盘文件里放的数据都是紧挨在一起的
0xdfs3439399abc0sfsdkslf9sdfpsfds0xdfs3439399abc0sfsdkslf9sdfpsfds
0xdfs3439399abc0sfsdkslf9sdfpsfds0xdfs3439399abc0sfsdkslf9sdfpsfds
磁盘里存放的数据看起来如上所示,可能先有一个extent组开始的一些东西,然后里面是一个一个的extent,每个extent开始的时候会写一些特殊的信息,然后再是一个一个的数据页,里面是一个一个的数据行。
那么在读取一个数据页的时候,就可以通过随机读写的方式来了。如下伪代码:
dataFile.setStartPosition(25347)
dataFile.setEndPosition(28890)
dataPage = dataFile.read()
由此指定磁盘文件的开始和截止位置,就能读取出来指定位置的一段数据,比如读取出
来一大坨东西:psfds0xdfs343939。也许这坨东西就是一个数据页包含的内容了。然后把数据页放在内存的缓存页里即可。
接着CRUD操作都可以直接针对缓存页去执行了,会自动把更新的缓存页加入flush链表,然后更新它在LRU链表里的位置,包括管宁割席后的缓存页会从free链表中拿出来等等。
此时对于那些被更新过的缓存页来说,都会由后台线程刷入磁盘额
刷磁盘的时候是怎么刷的?
伪代码如下:
dataFile.setStartPosition(25347)
dataFile.setEndPosition(28890)
dataFile.write(cachePage)
因为一个数据页的大小都是固定的,所以一个数据页固定就是可能在一次磁盘文件里占据了某个开始位置到结束位置的一段数据,此时你歇会去也是一样的,选择好固定的一段位置的数据,直接把缓存页的数据写回去,就覆盖了原来的那个数据