当前位置: 首页> 娱乐> 明星 > 企业名录怎么导出_石家庄裕华区最新疫情_广州seo软件_百度提升排名

企业名录怎么导出_石家庄裕华区最新疫情_广州seo软件_百度提升排名

时间:2025/8/10 10:28:14来源:https://blog.csdn.net/qq_38257958/article/details/144192890 浏览次数:0次
企业名录怎么导出_石家庄裕华区最新疫情_广州seo软件_百度提升排名

目录

1. InnoDB记录类型

1.1 相关语法

2. Compact

2.1 记录的额外信息

2.1.1 变长字段长度列表

2.1.1.1 占用的字节数,计算规则

2.1.1.1.1 前置条件

2.1.1.1.2 计算规则

2.1.1.1.3 案例演示

2.1.2 NULL列表

2.1.2.1 前置条件

2.1.2.2 案例演示

2.1.2.2.1 第一条记录

2.1.2.2.2 第二条记录

2.1.3 记录头信息

2.2 记录的真实数据

2.3 CHAR(M) 列的存储格式

3. Redundant

3.1 记录头信息

3.1.1 1byte_offs_flag

3.1.1.1 1byte_offs_flag 的值是如何确定的

3.2 Redundant 行格式中 NULL 值的处理

3.2.1 案例分析

3.3 CHAR(M) 列的存储格式

4 行溢出数据

4.1 VARCHAR(M) 最多能存储的数据

4.1.1 其他字符集

4.2 记录中的数据太多产生的溢出

4.3 行溢出的临界点

5 Dynamic 和 Compressed 行格式


1. InnoDB记录类型

  • Compact
  • Redundant
  • Dynamic
  • Compressed

1.1 相关语法

CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名称

ALTER TABLE 表名 ROW_FORMAT=行格式名称

2. Compact

主要由两部分组成,明细如下:

  • 记录的额外信息
    • 变长字段长度列表
    • NULL值列表
    • 记录头信息
  • 记录的真实数据

2.1 记录的额外信息

2.1.1 变长字段长度列表

变长字段包括:VARCHAR(M)、VARBINARY(M)、TEXT、BLOB 等

  • 真正的数据内容
  • 占用的字节数
2.1.1.1 占用的字节数,计算规则
2.1.1.1.1 前置条件
  • 假设某个字符集中表示一个字符最多需要使用的字节数为 W,也就是使用 SHOW CHARSET 语句的结果中的 Maxlen 列,比方说 utf8 字符集中的 W 就是 3,gbk 字符集中的 W 就是 2,ascii 字符集中的 W 就是 1
  • 对于变长类型 VARCHAR(M) 来说,这种类型表示能存储最多 M 个字符(注意是字符不是字节),所以这个类型能表示的字符串最多占用的字节数就是 M × W
  • 假设它实际存储的字符串占用的字节数是 L
2.1.1.1.2 计算规则
  • M × W <= 255 : 占用 1 个字节
  • M × W  >  255
    • L <= 127 : 占用 1 个字节
    • L  >  127 : 占用 2 个字节

PS : 字节的第一个二进制位作为标志位,如果该字节的第一个位为 0,那该字节就是一个单独的字段长度(使用一个字节表示不大于 127 的二进制的第一个位都为 0),如果该字节的第一个位为1,那该字节就是半个字段长度

2.1.1.1.3 案例演示

创建表

CREATE TABLE record_format (
    c1 VARCHAR(10),
    c2 VARCHAR(10) NOT NULL,
    c3 CHAR(10),
    c4 VARCHAR(10)
) CHARSET=ascii ROW_FORMAT=COMPACT;

插入数据 

INSERT INTO `record_format`(`c1`, `c2`, `c3`, `c4`) VALUES ('1111', '222', '33', '4'),('5555', '666', null, null);

结果数据

其中 c1、c2、c4 属于变长字段,record_format 表的字符集是 ascii (Maxlen 为 1,即 W 为 1),字段 c1、c2、c4 的 M 都为 10,所以占用一个字节(M × W <= 255),最终数据是 01 03 04(逆序保存,第一个标志位为 0,表示单独的字节长度)

PS:变长字段长度列表中只存储值为非 NULL 的列内容占用的长度,值为 NULL 的列的长度是不储存的 。也就是说对于第二条记录来说,因为 c4 列的值为 NULL,所以第二条记录的变长字段长度列表只需要存储 c1 和 c2 列的长度即可

2.1.2 NULL列表
2.1.2.1 前置条件
  • 主键列、被 NOT NULL 修饰的列都是不可以存储 NULL 值的,所以在统计的时候不会把这些列算进去。比方说表 record_format 的 3 个列 c1、c3、c4 都是允许存储 NULL 值的,而 c2 列是被 NOT NULL 修饰,不允许存储 NULL 值
  • 如果表中没有允许存储 NULL 的列,则 NULL 值列表也不存在了,否则将每个允许存储NULL的列对应一个二进制位,二进制位按照列的顺序逆序排列,二进制位表示的意义如:
    • 二进制位的值为 1 时,代表该列的值为 NULL
    • 二进制位的值为 0 时,代表该列的值不为 NULL
  • MySQL 规定 NULL 值列表必须用整数个字节的位表示,如果使用的二进制位个数不是整数个字节,则在字节的高位补 0。因此如果一个表中有 9 个允许为 NULL,那这个记录的 NULL 值列表部分就需要 2 个字节来表示了。
2.1.2.2 案例演示
2.1.2.2.1 第一条记录

案例 2.1.1.1.3 中,record_format 表允许为 NULL 的列有 c1、c3、c4 。对于第一条记录,这些列都不为 NULL,图示如下:

所以第一条记录的当前的数据为:01 03 04 00

2.1.2.2.2 第二条记录

对于第二条记录,c3、c4 为 NULL,图示如下:

所以第二条记录的当前的数据为:03 04 06

2.1.3 记录头信息

记录头信息,它是由固定的5个字节组成,明细如下:

名称大小(bit描述
预留位11没有使用
预留位21没有使用
delete_mask1标记该记录是否被删除
min_rec_mask1B+树的每层非叶子节点中的最小记录都会添加该标记
n_owned4表示当前记录拥有的记录数
heap_no13表示当前记录在记录堆的位置信息
record_type3表示当前记录的类型,0表示普通记录,1表示B+树非叶子节点记录,2表示最小记录,3表示最大记录
next_record16表示下一条记录的相对位置

2.2 记录的真实数据

对于 record_format 表来说,记录的真实数据除了 c1、c2、c3、c4 这几个我们自己定义的列的数据以外,MySQL 会为每个记录默认的添加一些列(也称为隐藏列),具体的列如下:

列名是否必须占用空间描述
DB_ROW_ID6字节ID,唯一标识一条记录
DB_TRX_ID6节字事务ID
DB_ROLL_PTR7字节回滚指针

 InnoDB 表对主键的生成策略:优先使用用户自定义主键作为主键,如果用户没有定义主键,则选取一个 Unique 键作为主键,如果表中连 Unique 键都没有定义的话,则 InnoDB 会为表默认添加一个名为 DB_ROW_ID 的隐藏列作为主键。

0~6、空格 的 ascii 码分别 48 ~ 54、20 ,则记录结构如下所示:

2.3 CHAR(M) 列的存储格式

案例中的 record_format 表采用的是 ascii 字符集,这个字符集是一个定长字符集,也就是说表示一个字符采用固定的一个字节,如果采用变长的字符集(也就是表示一个字符需要的字节数不确定,比如 gbk 表示一个字符要 1~2 个字节、utf8 表示一个字符要 1~3 个字节等)的话,c3 列的长度也会被存储到变长字段长度列表中

变长字符集的 CHAR(M) 类型的列要求至少占用 M 个字节,而 VARCHAR(M) 却没有这个要求。比方说对于使用 utf8 字符集的 CHAR(10) 的列来说,该列存储的数据字节长度的范围是10~30个字节。即使我们向该列中存储一个空字符串也会占用 10 个字节,这是怕将来更新该列的值的字节长度大于原有值的字节长度而小于 10 个字节时,可以在该记录处直接更新,而不是在存储空间中重新分配一个新的记录空间,导致原有的记录空间成为所谓的碎片

3. Redundant

Redundant 记录格式如下:

与 Compact 记录差异:

  • Compact记录存在变长字段长度列表NULL值列表,Redundant 记录存在字段长度偏移列表
  • Compact记录头信息占用  5 个字节,Redundant 记录头信息占用 6 个字节

假设上述两个记录如下所示:

第一条记录的字段长度偏移列表就是:25 24 1A 17 13 0C 06

因为它是逆序排放的,所以按照列的顺序排列就是:06 0C 13 17 1A 24 25

按照两个相邻数值的差值来计算各个列值的长度的意思就是:

  • 第一列(`row_id`)的长度就是 0x06个字节,也就是 6 个字节
  • 第二列(`transaction_id`)的长度就是 (0x0C - 0x06)个字节,也就是 6 个字节
  • 第三列(`roll_pointer`)的长度就是 (0x13 - 0x0C)个字节,也就是 7 个字节
  • 第四列(`c1`)的长度就是 (0x17 - 0x13)个字节,也就是 4 个字节
  • 第五列(`c2`)的长度就是 (0x1A - 0x17)个字节,也就是 3 个字节
  • 第六列(`c3`)的长度就是 (0x24 - 0x1A)个字节,也就是 10 个字节
  • 第七列(`c4`)的长度就是 (0x25 - 0x24)个字节,也就是 1 个字节

3.1 记录头信息

Redundant 行格式的记录头信息占用 6 字节,48 个二进制位,明细如下:

名称大小(bit描述
预留位11没有使用
预留位21没有使用
delete_mask1标记该记录是否被删除
min_rec_mask1B+树的每层非叶子节点中的最小记录都会添加该标记
n_owned4表示当前记录拥有的记录数
heap_no13表示当前记录在记录堆的位置信息
n_field10表示记录中列的数量
1byte_offs_flag1标记字段长度偏移列表中每个列对应的偏移量是使用1字节还是2字节表示的
next_record16表示下一条记录的相对位置

与 Compact 行格式的记录头信息对比来看,有两处不同:

  • Redundant 行格式多了 n_field 和 1byte_offs_flag 这两个属性
  • Redundant 行格式没有 record_type 这个属性
3.1.1 1byte_offs_flag
  • 1:使用  1 字节记录 字段长度偏移列表  中每个列对应的偏移量
  • 0:使用  2 字节记录 字段长度偏移列表  中每个列对应的偏移量
3.1.1.1 1byte_offs_flag 的值是如何确定的
  • 当记录的真实数据占用的字节数不大于 127 时,每个列对应的偏移量占用1个字节
  • 当记录的真实数据占用的字节数大于 127,但不大于 32767 时,每个列对应的偏移量占用 2 个字节
  • 真实数据大于 32767 在本页中只保留前  768 个字节和 20 个字节的溢出页面地址,使用 2 个字节来存储偏移量

所以对于第一条记录来说一共有 37 (0x00 ~ 0x24)个字节,小于 127,所以行记录的 1byte_offs_flag 为 1

3.2 Redundant 行格式中 NULL 值的处理

列对应的偏移量值的第一个比特位作为是否为 NULL 的依据,该比特位也可以被称之为 NULL比特位。如果值为1,那么该列的值就是 NULL,否则不是 NULL

  • 如果存储 NULL 值的字段是定长类型的,比方说 CHAR(M) 数据类型的,则 NULL 值也将占用记录的真实数据部分,并把该字段对应的数据使用 0x00 字节填充
  • 如果该存储 NULL 值的字段是变长数据类型的,则不在记录的真实数据处占用任何存储空间
3.2.1 案例分析

我们继续以案例来分析,第二条记录的 字段长度偏移列表 为:A4 A4 1A 17 13 0C 06

因为它是逆序排储存的,所以按照列的顺序排列就是:06 0C 13 17 1A A4 A4

c3 列对应的偏移量为 0xA4,它对应的二进制实际是:10100100,可以看到最高位为 1,意味着该列的值是 NULL。将最高位去掉后的值变成了0100100,对应的十进制值为 36,而 c2 列对应的偏移量为 0x1A,也就是十进制的 26。36 - 26 = 10,也就是说最终 c3 列占用的存储空间为 10 个字节。
c4 列是VARCHAR(10)类型的,VARCHAR(10)是一个变长数据类型,c4列对应的偏移量为0xA4,与 c3 列对应的偏移量相同,这也就意味着它的值也为NULL,将0xA4的最高位去掉后对应的十进制值也是36,36 - 36 = 0,也就意味着c4列本身不占用任何记录的实际数据处的空间

3.3 CHAR(M) 列的存储格式

Compact 行格式在 CHAR(M) 类型的列中存储数据的时候分变长字符集和定长字符集的情况,而在 Redundant 行格式中只要是使用 CHAR(M) 类型,占用的真实数据空间就是该字符集表示一个字符最多需要的字节数和M的乘积。比方说使用 utf8 字符集的 CHAR(10) 类型的列占用的真实数据空间始终为 30 个字节,使用 gbk 字符集的 CHAR(10) 类型的列占用的真实数据空间始终为 20 个字节

4 行溢出数据

4.1 VARCHAR(M) 最多能存储的数据

VARCHAR(M) 类型的列最多可以占用 65535 个字节。其中的 M 代表该类型最多存储的字符数量,如果我们使用 ascii 字符集的话,一个字符就代表一个字节

我们可以发现创建表的时候,抛出了异常,那是因为在上文中,我们分析得出,每列占用的空间可能包含三个部分:

  • 真实数据
  • 真实数据占用字节的长度
  • NULL值标识,如果该列有NOT NULL属性则可以没有这部分存储空间

其中 真实数据占用字节的长度最大需要 2 个字节,NULL 值标识占用 1 个字节 (1bits,不足补0,凑整),所以允许为 NULL 的情况下,真实数据最多占用 65532  个字节,不允许为 NULL 的情况下,真实数据最多占用 65533 个字节,案例演示如下:

4.1.1 其他字符集

如果 VARCHAR(M) 类型的列使用的不是 ascii 字符集,那M的最大取值取决于该字符集表示一个字符最多需要的字节数。在列的值允许为 NULL 的情况下,gbk 字符集表示一个字符最多需要 2 个字节,那在该字符集下,M的最大取值就是 32766(65532 / 2),也就是说最多能存储 32766 个字符;utf8 字符集表示一个字符最多需要 3 个字节,那在该字符集下,M的最大取值就是 21844,就是说最多能存储 21844(65532 / 3)个字符。案例演示如下: 

PS : 上述案例中都是只有一个字段,如果有多个字段则为所有列(不包括隐藏列和记录头信息)占用的字节长度加起来不能超过 65535 个字节 

4.2 记录中的数据太多产生的溢出

MySQL 中磁盘和内存交互的基本单位是页,也就是说MySQL是以页为基本单位来管理存储空间的,我们的记录都会被分配到某个页中存储。而一个页的大小一般是 16KB,也就是 16384 字节,而一个 VARCHAR(M) 类型的列就最多可以存储 65532 个字节,这样就可能造成一个页存放不了一条记录的尴尬情况

在 Compact 和 Redundant 行格式中,对于占用存储空间非常大的列,在记录的真实数据处只会存储该列的一部分数据,把剩余的数据分散存储在几个其他的页中,然后记录的真实数据处用20个字节存储指向这些页的地址(当然这20个字节中还包括这些分散在其他页面中的数据的占用的字节数),从而可以找到剩余数据所在的页。Compact 溢出页如下所示:

我们把这个过程叫做 行溢出,存储超出768字节的那些页面被称为 溢出页

4.3 行溢出的临界点
  • MySQL中规定一个页中至少存放两行记录
  • 一个页也会含有其他额外信息,占用 132 字节
  • 每个记录需要的额外信息是 27 字节
    • 2个字节用于存储真实数据的长度
    • 1个字节用于存储列是否是NULL值
    • 5个字节大小的头信息
    • 6个字节的 DB_ROW_ID
    • 6个字节的 DB_TRX_ID 
    • 7个字节的 DB_ROLL_PTR 

根据以上结论得出以下公式:

132 + 2 × (27 + n) < 16384

也就是说如果一个列中存储的数据小于8099个字节,那么该列就不会成为 溢出列,但这只是针对表只有一个表来说的,如果表中有多个列,则需要修改公式

5 Dynamic 和 Compressed 行格式

MySQL 5.7 默认行格式就是 Dynamic,这俩行格式和 Compact 行格式挺像,只不过在处理行溢出数据时有点儿分歧,它们不会在记录的真实数据处存储字段真实数据的前768个字节,而是把所有的字节都存储到其他页面中,只在记录的真实数据处存储其他页面的地址

Compressed 行格式和 Dynamic 不同的一点是,Compressed 行格式会采用压缩算法对页面进行压缩,以节省空间。

关键字:企业名录怎么导出_石家庄裕华区最新疫情_广州seo软件_百度提升排名

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: