mysql数据存储格式

mysql数据存储格式

mysql的最小存储单位是页,一页是16KB,页里面放的是记录,记录的存放格式叫做行格式

mysql个一个对象分配一个段(一个表,或者一个索引就是分配一个 段segment),一个段里面有多个区(1M),一个区里面有多个页,页里存的记录是按照行格式存储。

页的构成

页有7个构成部分,除去数据部分一个页大概需要128(如果4个字节用于不确定的三个区域)

image-20250903173320475

页里面,File Header的38字节构成

image-20250903175021261

mysql页数据变换过程

image-20250904174925323

mysql一条记录的构成,行格式使用compact的时候

image-20250904175044648

记录头说明
  • 预留位1、2:暂未使用
  • delete_mask:当前记录被删除的标志位
  • min_rec_maskB+树的每层非叶子节点中的最小记录的标志位(感觉和record_type是重复的)
  • n_owned:当前记录组(槽)里面有多少条数据
  • heap_no:当前记录在记录堆中的位置,最小记录是0,最大是1,普通记录是2开始增加,也就是记录编号
  • record_type:当前记录类型。具体地,0: 普通记录;1: B+树非叶子节点记录(即所谓的目录项记录);2: 最小记录;3: 最大记录
  • next_record:下一条记录的相对位置(这个是下一条记录对当前的偏移量)

可变字段长度

对varchar之类的可变长度会在这里记录字符的长度,并且是倒序存放,比如有4个字段,ID,name(char(32)),des1(varchar(256)),des2(varchar(256)),真实数据是 1,张三,a,abc
会记录03 01(倒数第一可变字段用了3个字节,倒数第二可变字段用了1个字节),

一个变长字段需要用额外2个字节来存储,mysql字段varchar字段最大65535也是2的16次方只能表示这么多来决定的(出去0),实际还要出去2字节的变长标记信息,也就是说单字段非空的情况允许65533字节。一页是16K小于65535,这时候会行溢出,这样的一个字段是用多个页来存储的。compact只会只会存768个字节,溢出部分放到别的地方。

空值列表

用于记录可以为null的字段些字段是null依旧是到这放,用bitmap 类似方式存放,比如一共有2个字段可以是null,并且最后一个字段真实的值是null,那么存放的结果是10(二进制的10),这时候一个字节可以表示8个这样的字段

mysql的行格式类型

不同行格式区别在于怎么记录可变字段的长度和空值字段,以及行溢出的时候怎么处理

redundant 和 compressed 记录可变字段的长度和空值字段一样
compact 和 dynanmic 记录可变字段的长度和空值字段一样(新版本)

  • redundant 5.0之前和compact 类似
  • compact , 5.1 默认,和dynanmic 的区别在于处理溢出字段的方式
  • dynanmic 5.7 以后默认
  • compressed 和dynanmic 类似区别在于也在空值列表和可变字段列表的头

image-20250905183157572

Redundant行格式是把可变字段列表和空值列表都放在字段偏移列表中

image-20250905183532633

行记录中的隐藏字段

image-20250905173343545

Page Directory里面存的事分槽信息

关于页里面组的概念(或者叫做槽)

页里面的记录会分成三类组,
最小值的组:只有一条,放最小值(不能放中间值,第三条数据是放在最大值的组里面的)
最大值的组:放最大值,并且添加中间数据的时候是从这里开始添加,当大于8条数据的时候分裂成2个组,一个普通记录值的组,一个最大值的组,分别4条,所以这个组里面的记录是1-8条

普通值的组:由最大值的组或者普通值的组分裂而来,所以是4-8条记录,在这个组里面添加记录依旧会满8分裂成2个4条的组。
image-20250905170019699

Page header的包含的字段和描述

image-20250905170541611

区的概念

mysql一页是16K一个区是1MB,页和页之间是双向链表,链表是一种随机存储结构,在传统磁盘中,巡道绕后的时间是比读取一次数据时间更久的,所以为了优化读写速度mysql定义了区的概念。

一个区是一个连续的空间,在读取一条批量连续数据的时候,如果这些数据在不同的页,并且这些数据在同一个区(或者尽量少的区)那么磁盘巡道的时间会明显减少,从而增加读写效率。

碎片区

对于特别小的数据会共用区,目的是避免一份很小的数据占用一一整个区的额存储(1M),在数据很小的时候不不同的表会同用一个区。碎片区直属于表空间,而不是换分到段下面。当一个表的数据占用32个页的碎片区空间以后,mysql会给他分配专属的区,并且这个区会归属对应的表下面的段下面。

段的概念

mysql一个对象是一个段,段其实的目的和区类似,段的概念是把类似的区尽量放在一起,一个表默认就是一个段,创建一个新的索引也是一个段。尽量让相关的数据放在一起。

posted on 2025-09-05 19:31  zhangyukun  阅读(17)  评论(0)    收藏  举报

导航