Mysql-InnoDB索引01:一条记录的存储结构之compact存储格式

mysql索引是java程序员面试中常见的一个话题,本系列打算用5个篇章来带大家彻底理解揭开mysql索引的神秘面纱。这五篇文章采用由小及大的顺序,一点点展开,先从一张表最基本单位-记录讲起,然后讲解盛放记录的盒子-表的存储结构,在大家理解了表的存储结构后,再去学习索引就事半功倍了。

  1. 行格式
    1. 行格式的分类
      我们平时存取数据都是以记录为单位进行的,这些记录在磁盘上的存储形式称为行格式。innodb指定了四种行格式:compact,redundant,dynamic和compressed。mysql可以在建表时指定行格式。
    2. 指定行格式
mysql> create database xiaohaizi;
Query OK, 1 row affected (0.01 sec)

mysql> use xiaohaizi;
Database changed
mysql> create table compact_fomat(c1 varchar(10),c2 varchar(10) not null,c3 varchar(10),c4 varchar(10))charset=ascii row_format=compact;
Query OK, 0 rows affected (0.08 sec)
insert into compact_fomat(c1,c2,c3,c4) values('aaaa','bbb','cc','d'),('eeee','fff',null,null);
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from compact_fomat;
+------+-----+------+------+
| c1   | c2  | c3   | c4   |
+------+-----+------+------+
| aaaa | bbb | cc   | d    |
| eeee | fff | NULL | NULL |
+------+-----+------+------+

  1. COMPACT行格式
    1. 结构示意图
      在这里插compact行格式示意图入图片描述
      图中黄色部分是该条记录的额外信息,蓝色部分才是记录的真实数据。
    2. 变长字段长度列表
      变长字段,如varchar占几个字节是不确定的,那么mysql是怎样判断某个长度范围是属于某列呢?变长字段长度列表存储了变长列所占用的字节数,且按照列的顺序逆序存放(下篇介绍为什么逆序)。
      1. 举例
        例如第一条记录c1 c2 c4
        都是变长,分别占4(‘aaaa’),3,1个字节,该记录变长字段列表为:
        在这里插入图片描述
        图中数字为十六进制。
      2. 变长字段本身长度的确定
        上文提到变长字段列表存储变长字段实际占据的字节数,1字节可以表达0-255的长度,超过255怎么办呢,直接占据两个字节?Innodb有一套规则。为了说清楚这套规则,首先定义三个符号:
        M:记录所在字符集表示一个字符所需最大字节数,例如utf8对应的M为3,即三个字节一定能够表示该字符集里的所有单个字符。
        W:变长类型所能存储的最大字符数,例如varchar(15),W=15
        L:变长类型字段实际占用的字节数,例如varchar(15)字段存储‘qbc’,则L=3
        MW:变长字段所占的最大字节数
        当进行数据存储的时候,首先计算M
        W的值,当该值小于等于255,则代表该处的属于,无论怎么存,其长度都不会超过255,所以使用一字节存储其长度即可。当MW>255,代表未来该处存储的字节长度有可能超过255,此时看L的值,如果L<=127,代表当前用一个字节也能存的下,使用一字节存储,当L>127,使用2字节存储。这种机制考虑的比较全面,不仅考虑了当下,还考虑了未来(MW)。当L>127时,最高位为1,小于127时,最高位为0.
        当读取记录的时候,首先查看该表结构,获取M 和W 值。计算M*W,如果<=255,读取长度列表的一个字节查看其长度,否则,查看第一个字节的最高位是否为1,为1的话读取两个长度,为0读取1个长度。
        我们知道,一页的容量为16kb,极端条件下,该页面全部用来存储一条记录的一个字段,它所占的字节为2^16个,用两字节来表示它所占字节完全足够。
    3. 空值列表
      如果一条记录为空,把它存储到真实数据区会很占用存储空间。例如char(10)类型,即使为空也要开辟10个字符的空间存储 全部填0。于是innodb设计了空值列表。innodb会统计表中可能为null的列(非主键 非 not null 修饰),然后以逆序在空值列表处以一个bit代表其状态,为1,代表为空,为0代表非空。例如c1 c3 c4 列允许为空,此时:

在这里插入图片描述
3. 记录头信息
记录头信息描述记录的一些属性,占4个字节
在这里插入图片描述
4. 记录真实数据
记录真实数据区除了存储用户存储的数据外,还有三个隐藏列。
在这里插入图片描述
其中row_id代表该记录的主键列的值(或者说为能唯一确定该列的值),当用户已经定义了主键,或者用户没有定义主键,但是记录中存在 not null与unique限定的列,优先以它们唯一确定该条记录,此时row_id
不会被添加,如果不满足上述两种情况,才会添加该列。tx_id
为事务id(讲事务的时候会讲到)。roll_pointer为回滚指针(将日志的时候讲到)。

参考《mysql是怎样运行的》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

弈师亦友

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值