MySQL表(二)-InnoDB 行 记录格式

InnoDB 行 记录格式

在InnoDB 1.0.x版本之前,InnoDB存储引擎提供了Compact和Redundant两种格式 来存放 行记录数据,这也是目前使用最多的一种格式
Redundant格式是为兼容之前版本而保留的
在MySQL 5.1版本中,默认设置为Compact行格式
可以通过命令SHOW TABLE STATUS LIKE 'table_name'来查看当前表使用的行格式,其中row_format属性表示当前所使用的行记录结构类型

Compact行记录格式

Compact行记录是在MySQL 5.0中引入的,其设计目标是高效地存储数据
一个页中存放的行数据越多,其性能就越高
在这里插入图片描述

Compact行记录格式的首部 是一个 非NULL变长字段 长度列表,并且其是 按照 列的顺序逆序 放置的,其长度为:

  • 若列的长度小于255字节,用1字节表示
  • 若大于255个字节,用2字节表示

变长字段的长度最大不可以超过2字节,因在MySQL数据库中VARCHAR类型的最大长度限制为65535
变长字段之后的第二个部分是NULL标志位该位指示了 该行数据中 是否有 NULL值,有则用1表示。该部分所占的字节应该为1字节
接下来的部分是记录头信息(record header),固定占用5字节(40位)

在这里插入图片描述
最后的部分 就是 实际存储每个列的数据
需要特别注意的是,NULL不占该部分任何空间,即NULL除了占有NULL标志位,实际存储不占有任何空间
另外有一点需要注意的是,每行数据除了用户定义的列外,还有两个隐藏列,事务ID列和回滚指针列,分别为6字节和7字节的大小
若InnoDB表没有定义主键,每行还会增加一个6字节的rowid列

Redundant行记录格式

Redundant是MySQL 5.0版本之前InnoDB的行记录存储方式,MySQL 5.0支持Redundant是为了兼容之前版本的页格式
在这里插入图片描述
不同于Compact行记录格式,Redundant行记录格式的首部 是一个 字段长度 偏移列表,同样 是按照 列的顺序逆序放置的

  • 若列的长度小于255字节,用1字节表示
  • 若大于255字节,用2字节表示
    第二个部分为记录头信息(record header),不同于Compact行记录格式,Redundant行记录格式的记录头占用6字节(48位)
    在这里插入图片描述

n_fields值代表一行中列的数量,占用10位,这也很好地解释了为什么MySQL数据库一行支持最多的列为1023
另一个需要注意的值为1byte_offs_flags,该值定义了偏移列表占用1字节还是2字节
而最后的部分就是实际存储的每个列的数据了

行 溢出数据

InnoDB存储引擎可以将一条记录中的某些数据存储在真正的数据页面之外
一般认为BLOB、LOB这类的大对象列类型的存储会把数据存放在数据页面之外
这个理解有点偏差,BLOB可以不将数据放在溢出页面,而且即便是VARCHAR列数据类型,依然有可能被存放为行溢出数据

很多DBA喜欢MySQL数据库提供的VARCHAR类型
相对于Oracle VARCHAR2最大存放4000字节,SQL Server最大存放8000字节,MySQL数据库的VARCHAR类型可以存放65535字节
但是,如果创建VARCHAR长度为65535的表,会得到下面的错误信息

Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs【解决方法】:https://help.aliyun.com/document_detail/188724.html
TraceId : 0bc3b4ad16287757668774812e4726

从错误消息可以看到InnoDB存储引擎并不支持65535长度的VARCHAR
这是因为还有别的开销,通过实际测试发现能存放VARCHAR类型的最大长度为65532

需要注意的是,如果在执行创建表的时候没有将SQL_MODE设为严格模式,或许可以建立表,但是MySQL数据库会抛出一个warning

Message:Converting column'a'from VARCHAR to TEXT

warning信息提示了这次可以创建是因为MySQL数据库自动地将VARCHAR类型转换成了TEXT类型
SQL_MODE参数如下:
在这里插入图片描述

如果字符集换成GBK又或UTF-8的,会产生怎样的结果?

ERROR 1074(42000):Column length too big for column'a'(max=32767);use BLOB or TEXT instead
ERROR 1074(42000):Column length too big for column'a'(max=21845);use BLOB or TEXT instea

两次报错对max值的提示是不同的
因此从这个例子中 也应该理解 VARCHAR(n) 中的 n 指的是 字符的长度
而文档中说明VARCHAR类型最大支持65535,单位是字节

此外需要注意的是,MySQL官方手册中定义的65535长度是指所有VARCHAR列的长度总和,如果列的长度总和超出这个长度,依然无法创建

Row size too large.The maximum row size for the used table type,not counting BLOBs,is 65535.You have to change some columns to TEXT or BLOBs

InnoDB存储引擎的页为16KB,即16384字节,怎么能存放65532字节呢?
在一般情况下,InnoDB存储引擎的数据 都是 存放在 页类型为B-tree node中
但是当发生行溢出时,数据 存放在 页类型 为 Uncompress BLOB页 中
对于行溢出数据,采用如下方式存储数据:
在这里插入图片描述
那 多长的VARCHAR 是保存在 单个 数据页中的,从多长开始 又会保存在 BLOB页 呢?
可以这样进行思考:InnoDB存储引擎表是索引组织的,即B+Tree的结构,这样 每个页中 至少 应该有 两条行记录(否则失去了B+Tree的意义,变成链表了)
因此,如果 页中 只能存放下 一条记录,那么InnoDB存储引擎 会自动 将行数据 存放到 溢出页中

建立一个列为varchar(8098)的表,可以发现此时的行记录都是存放在数据页中,而不是在BLOB页中了,超过这个长度,就会保存在BLOB页中

另一个问题是,对于TEXT或BLOB的数据类型,总是以为它们是存放在Uncompressed BLOB Page中的
其实这也是不准确的,是放在数据页中还是BLOB页中,和上面的VARCHAR一样,至少保证一个页能存放两条记录

Compressed和Dynamic行记录格式

InnoDB 1.0.x版本开始引入了新的文件格式(file format,用户可以理解为新的页格式),以前支持的Compact和Redundant格式称为Antelope文件格式,新的文件格式称为Barracuda文件格式
Barracuda文件格式下拥有两种新的行记录格式:Compressed和Dynamic

新的两种记录格式 对于 存放在 BLOB中的数据 采用了 完全的 行溢出的方式
在数据页中 只存放 20个字节的指针,实际的数据都存放在Off Page中,而之前的Compact和Redundant两种格式会存放768个前缀字节

在这里插入图片描述
Compressed行记录格式的另一个功能就是,存储在其中的行数据会以zlib的算法进行压缩,因此对于BLOB、TEXT、VARCHAR这类大长度类型的数据能够进行非常有效的存储

CHAR的行结构存储

通常理解VARCHAR是存储变长长度的字符类型,CHAR是存储固定长度的字符类型
在上面的行结构的内部的存储中,可以发现 每行的 变长字段长度 的 列表 都没有存储 CHAR类型的长度

从MySQL 4.1版本开始,CHAR(N)中的N 指的是 字符的长度,而不是之前版本的 字节长度
也就说在不同的字符集下,CHAR类型列内部存储的可能不是定长的数据

对于 多字节字符编码 的 CHAR数据类型 的 存储,InnoDB存储引擎 在内部 将其视为 变长字符类型
这也就意味着 在变长长度列表中 会记录 CHAR数据类型的长度

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值