索引是在存储引擎中实现的,存储引擎负责对表中数据的读取和写入工作,不同存储引擎中数据的存放格式是不同的
为什么要学习页结构与行格式
学习页结构与行格式可以让我们知道数据项在底层是如何存储的,是以什么数据结构存储的,这让我们对其他内容的理解更加深刻
innodb数据存储格式(页)
innodb将数据划分为若干个16kb的页,以页作为磁盘和内存之间交互的基本单位,数据库io操作的最小单位是页
页之间在物理层面上不相连,通过双向链表连接。每个页中的数据项记录会按主键值的大小组成一个单向链表,并且每个页还为对应的单向链表生成了一个页目录,使得可以通过二分查找来加速页内数据的查找
页如果按类型划分,常见的有数据页,系统页,Undo页,事务数据页等
页中区域可分为文件头,文件尾,空闲空间,用户记录,最大最小记录,页目录,页面头部
- 文件头用来描述各种页的通用信息,包括页的编号,页的类型,上一页对应编号,下一页对应编号
- 文件头和文件尾都有校验和这个字段,校验和可以看做是一个页的标识,可以用来保证页在进行磁盘与内存间交互的一个完整性
- 用户记录中存储着按指定行格式存储的数据,相互之间形成一个单链表,而最大最小记录这是这个链表的头结点与尾结点
- 页目录,页目录并不会记录每条记录的数据,而是将数据分成一些小组,再记录每个小组最后一条记录的地址偏移量,每一组的地址偏移量我们称之为槽位 (之所以槽位指向每一小组的最后一个记录,我的理解是:更好地利用槽位与小组数据的对应关系,因为最小记录自成一个分组,并且0号槽位指向的是最小记录的一下偏移量,那么通过0号槽位就可以直接找到1号分组对应的偏移地址,就没有必要再让1号槽位来指向1号分组的头部了)
- 页面头部,记录着页目录中槽位的数量,未使用空间的起始地址,第一个标记为已删除的记录地址,本页中所有记录总数等等
innodb行格式
查看行格式命令:show table status like ‘表名’;
行格式有:compact,dynamic,compressed,redundant
mysql8.0默认使用dynamic行格式
我们数据的插入是以行为单位进行插入操作的
compact,dynamic,compressed行格式包括变长字段长度列表(用来记录变长字段的长度),null值列表(如果字段允许null值的话,那么便会有一个对应的比特位记录该处的值是否为空),记录头信息,用户数据
记录头信息中有几个关键字段:
- 删除标记字段(标记该行记录是否被删除,如果记录被删除了,则该字段置1,之所以不直接删除是为了节省时间,如果直接删除某一条记录的话,需要修改其他记录在磁盘当中的位置,消耗性能。所以只是打一个删除标记)
- 记录类型字段(0表示普通记录,1表示非叶子节点记录,2表示最小记录,3表示最大记录)
- 位置字段 (表示该记录在本页当中的位置标号)
- 小组数量字段( 与页目录共同实现加速查找)
- 下一数据地址偏移量(维护链表,未删除的数据形成一条链表,删除的数据形成另一条链表)
当一些变长字段过长时,超出一个页所能存出的容量,compact与redundant行格式会只存入一部分数据,剩余部分分散存储在其他页中;而dynamic与compressed行格式采用了完全溢出的方式,把数据完全放在溢出页当中
数据库结构
数据库自上而下的结构为表空间,段,区,页,行
为什么要有区 :因为页与页之间是通过双向链表维护的,如果不加以其他限制,那么页与页之间在磁盘当中的物理位置可能相距很远,这样的随机io使得通过链表访问速度很慢,引入区的概念,就是为了让页与页之间尽可能的在物理上是连续的
为什么要有段,段则用来区分叶子结点与非叶子节点的页,提高顺序扫描叶子结点的效率