导图社区 第四章
从根上理解 MySQL,把所有变长字段的真实数据占用的字节长度都存放在记录的开头部位,从而形成一个变长字段长度列表,各变长字段数据占用的字节数按照列的顺序。
社区模板帮助中心,点此进入>>
英语词性
互联网9大思维
组织架构-单商户商城webAPP 思维导图。
法理
刑法总则
【华政插班生】文学常识-先秦
【华政插班生】文学常识-秦汉
文学常识:魏晋南北朝
【华政插班生】文学常识-隋唐五代
民法分论
第四章
1. InnoDB 页简介
InnoDB 存储引擎数据存储位置
数据存储在磁盘中
InnoDB 存储引擎数据处理方式
从磁盘中读取数据到内存
在内存中处理 MySQL 请求
将处理结果写回磁盘
存在问题
磁盘读写速度太慢
解决方案
将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位,InnoDB 中页的大小一般为 16KB
2. InnoDB 行格式
类型
Compact
Redundat
Dynamic
Compressed
指定行格式
创建时指定
CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名称
修改时指定
ALTER TABLE 表名 ROW_FORMAT=行格式名称
案例数据
3. Compact
总体结构模型图
记录的额外信息
变长字段长度列表
变长字段是什么
VARCHAR、BOLB、TEXT......
变长字段占用的存储空间
真实数据占用的字节数
记录真实长度占用的字节数
变长字段长度列表是什么
把所有变长字段的真实数据占用的字节长度都存放在记录的开头部位,从而形成一个变长字段长度列表,各变长字段数据占用的字节数按照列的顺序逆序存放
怎么填充
计算一行中那些变长类型的列的数据长度,得到长度的十六进制值,并且按列的逆序填充进该列表
用一个还是两个字节表示变长字段的长度
前置知识
W
假设某个字符集中表示一个字符最多需要使用的字节数为 W
M
对于变长类型 VARCHAR(M) 来说,这种类型表示能存储最多 M 个字符
L
假设它实际存储的字符串占用的字节数是 L
表示规则
W * M <= 255
用一个字节表示变长字段长度
W * M > 255
L <= 127
L > 127
用两个字节表示变长字段长度
填充了变长字段列表的示意图
NULL 值列表
为什么需要这个
如果把这些 NULL 值都放到记录的真实数据中存储会很占地方,所以会将所有 NULL 值存储到 NULL 值列表中
怎么存储
统计表中允许存储 NULL 的列有哪些
使用二进制表示该列是否存了数据
二进制位 1 表示该列存储了数据
二进制为 0 表示该列为存储数据
补充高位
MySQL 规定 NULL值列表 必须用整数个字节的位表示,如果使用的二进制位个数不是整数个字节,则在字节的高位补 0
填充了 NULL 值列表的示意图
记录头信息
作用
用于描述记录
组成
5 个字节,40 个二进制位
每个二进制位的作用
记录的真实数据
默认列
MySQL 数据库会增加几个默认列
自定义列
就是自己创建的列
为什么 row_id 不是必须的?
因为这跟 InnoDB 的表主键的生成策略有关
优先使用用户自定义主键作为主键
如果用户没有定义主键,则选取一个 Unique 键作为主键
如果表中连 Unique 键都没有定义的话,则 InnoDB 才会为表默认添加一个名为 row_id 的隐藏列作为主键
总体结构示意图
4. Redundat
和 Compact 的区别点
字段长度偏移列表
同样通过列逆序的方式去记录
记录的值就是每一列距离起始点的距离
两个相邻值相减的结果就是一列数据的长度
少了 record_type 列,多了 n_filed 和 1byte_offs_flag 列
n_field
记录总列数
1byte_offs_flag
用于标记每一列的偏移量是用一个字节表示还是用两个字节表示
NULL 值处理
没有 NULL 值列表
但是通过将列对应的偏移量的第一个比特位作为是否为 NULL 值的标识
5. CHAR(M)
在 Compact 行格式中
对于 CHAR(M) 类型的列来说,当列采用的是定长字符集(ASCII)时,该列占用的字节数不会被加到变长字段长度列表,而如果采用变长字符集时(GBK),该列占用的字节数也会被加到变长字段长度列表
变长字符集的 CHAR(M) 类型的列要求至少占用 M 个字节,而 VARCHAR(M) 却没有这个要求
防止更新该类型的数据时产生碎片
在 Redundat 行格式中
Redundant 行格式中,不管该列使用的字符集是啥,只要是使用 CHAR(M) 类型,占用的真实数据空间就是该字符集表示一个字符最多需要的字节数和 M 的乘积
CHAR(10) 在 ASCII 中占用 10 * 1 个字节
CHAR(10) 在 GBK 中占用 10 * 2 个字节
CHAR(10) 在 UTF8 中占用 10 * 3 个字节
6. 行数据溢出
VARCHAR(M) 最大存储量
设计上
该类型在设计上是是可存储 65535 个字节,即 VARCHAR(65535)
实际上
设计的占用字节数包含了三个方面
真实的数据(存入的数据)
真实的数据的长度占用的字节数(1 或 2 个字节)
NULL 值标识(1 个字节,当列设计为 NOT NULL 时则没有)
最终存储量
从字节看
VARCHAR 类型的列没有 NOT NULL 属性,那最多只能存储 65532 个字符的数据(65535 - 2 - 1)
VARCHAR 类型的列有 NOT NULL 属性,那最多只能存储 65533 个字符的数据(65535 - 2)
从字符看
分不同的字符类型讨论,比如
ASCII,1 个字符需要 1 个字节
65532 / 1(或者 65533 / 1)个字符
GBK,1 个字符需要 2 个字节
65532 / 2(或者 65533 / 2)个字符
UTF8,1 个字符需要 3 个字节
65532 / 3 (或者 65533 / 3)个字符
行数据溢出处理
一页最多存储 16KB 数据,即 16384 字节,但是 VARCHAR(M) 能够存储 65533 个字节的数据
在 Compact 和 Reduntant 行格式中,只记录前 768 字节,剩余的数据存放到其他地方,至于其他地方的地址跟在 768 个字节数据后面
行数据溢出时机
页空间利用情况
用于记录页的额外信息花费 136 个字节
每一行记录的额外信息 27 字节
存储数据
计算溢出边界值(假设只有一列数据,并且为 n)
136 + 2×(27 + n) > 16384
n > 8090
结论
无需关注具体多少字节会溢出,只需要知道当一行存储的数据量太大的话可能会导致溢出
7. Dynamic 和 Compressed
Dynamic、Compressed 与 Compact 的区别
在处理行溢出数据时存在不同,它们不会在记录的真实数据处存储字段真实数据的前 768 个字节,而是把所有的字节都存储到其他页面中,只在记录的真实数据处存储其他页面的地址
Dynamic 和 Compressed 的区别
Compressed 行格式会采用压缩算法对页面进行压缩,以节省空间