InnoDB存储引擎和大多数数据库一样(如Oracle和Microsoft SQL Server数据库),记录是以行的形式存储的。这意味着页中保存着表中一行行的数据。到MySQL 5.1时,InnoDB存储引擎提供了Compact和Redundant两种格式来存放行记录数据,Redundant是为兼容之前版本而保留的,如果你阅读过InnoDB的源代码,会发现源代码中是用PHYSICAL RECORD(NEW STYLE)和PHYSICAL RECORD(OLD STYLE)来区分两种格式的。MySQL 5.1默认保存为Compact行格式。你可以通过命令SHOW TABLE STATUS LIKE ‘table_name‘来查看当前表使用的行格式,其中row_format就代表了当前使用的行记录结构类型。例如:

cmf>show table status like 'users'\G
*************************** 1. row ***************************Name: usersEngine: InnoDBVersion: 10Row_format: CompactRows: 9Avg_row_length: 1820Data_length: 16384
Max_data_length: 0Index_length: 16384Data_free: 0Auto_increment: NULLCreate_time: 2016-02-04 21:16:46Update_time: NULLCheck_time: NULLCollation: utf8_general_ciChecksum: NULLCreate_options: Comment:
1 row in set (0.02 sec)

数据库实例的一个作用就是读取页中存放的行记录。如果我们知道规则,那么也可以读取其中的记录,如py_innodb_page_info工具。下面将具体分析各格式存放数据的规则。

Compact行记录格式

Compact行记录是在MySQL 5.0时被引入的,其设计目标是能高效存放数据。简单来说,如果一个页中存放的行数据越多,其性能就越高。Compact行记录以如下方式进行存储:

Compact行格式的首部是一个非NULL变长字段长度列表,而且是按照列的顺序逆序放置的。当列的长度小于255字节,用1字节表示,若大于255个字节,用2个字节表示,变长字段的长度最大不可以超过2个字节(这也很好地解释了为什么MySQL中varchar的最大长度为65 535,因为2个字节为16位,即216=1=65 535)。第二个部分是NULL标志位,该位指示了该行数据中是否有NULL值,用1表示。该部分所占的字节应该为bytes。接下去的部分是为记录头信息(record header),固定占用5个字节(40位),每位的含义见下表4-1。最后的部分就是实际存储的每个列的数据了,需要特别注意的是,NULL不占该部分任何数据,即NULL除了占有NULL标志位,实际存储不占有任何空间。另外有一点需要注意的是,每行数据除了用户定义的列外,还有两个隐藏列,事务ID列和回滚指针列,分别为6个字节和7个字节的大小。若InnoDB表没有定义Primary Key,每行还会增加一个6字节的RowID列。

下面用一个具体事例来分析Compact行记录的内部结构:

wubx>create table mytest (t1 varchar(10),t2 varchar(10),t3 char(10),t4 varchar(10)) engine=innodb charset=latin1 row_format=compact;
Query OK, 0 rows affected (0.12 sec)wubx>insert into mytest values('a','bb','bb','ccc');
Query OK, 1 row affected (0.04 sec)wubx>insert into mytest values('d','ee','ee','fff');
Query OK, 1 row affected (0.03 sec)wubx>insert into mytest values('d',NULL,NULL,'fff');
Query OK, 1 row affected (0.04 sec)wubx>select * from mytest\G
*************************** 1. row ***************************
t1: a
t2: bb
t3: bb
t4: ccc
*************************** 2. row ***************************
t1: d
t2: ee
t3: ee
t4: fff
*************************** 3. row ***************************
t1: d
t2: NULL
t3: NULL
t4: fff
3 rows in set (0.00 sec)

创建了mytest表,有4个列,t1、t2、t4都为varchar变长字段类型,t3为固定长度类型char。接着我们插入了3条有代表性的数据,接着打开mytest.ibd(启用了innodb_file_per_table,若你没有启用该选项,请打开默认的共享表空间文件ibdata1)。在Windows下,可以选择用UltraEdit打开该二进制文件(在Linux环境下,使用hexdump -C -v mytest.ibd>mytest.txt即可),打开mytest.txt文件,找到如下内容:

$ hexdump -C -v mytest.ibd > mytest.txt
$ less mytest.txt
0000c070  73 75 70 72 65 6d 75 6d  03 02 01 00 00 00 10 00  |supremum........|
0000c080  2c 00 00 00 33 1e 00 00  00 00 81 51 25 9e 00 00  |,...3......Q%...|
0000c090  01 89 01 10 61 62 62 62  62 20 20 20 20 20 20 20  |....abbbb       |
0000c0a0  20 63 63 63 03 02 01 00  00 00 18 00 2b 00 00 00  | ccc........+...|
0000c0b0  33 1e 01 00 00 00 81 51  26 9f 00 00 01 8d 01 10  |3......Q&.......|
0000c0c0  64 65 65 65 65 20 20 20  20 20 20 20 20 66 66 66  |deeee        fff|
0000c0d0  03 01 06 00 00 20 ff 98  00 00 00 33 1e 02 00 00  |..... .....3....|
0000c0e0  00 81 51 2b a2 00 00 01  48 01 10 64 66 66 66 00  |..Q+....H..dfff.|

该行记录从0000c078开始,若整理如下,相信你会有更好的理解:
03 02 01             /*变长字段长度列表,逆序*/
00                 /*NULL标志位,第一行没有NULL值*/
00 00 10 00 2c          /*记录头信息,固定5字节长度*/
00 00 00 33 1e 00        /*RowID我们建的表没有主键,因此会有RowID*/
00 00 00 81 51 25        /*TransactionID*/
9e 00 00 01 89 01 10      /*Roll Pointer*/
61                 /*列1数据‘a‘*/
62 62               /*列2‘bb‘*/
62 62 20 20 20 20 20 20 20 20 /*列3数据‘bb‘*/
63 63 63             /*列4数据‘ccc‘*/

现在第一行数据就展现在我们眼前了。需要注意的是,变长字段长度列表是逆序存放的,03 02 01,而不是01 02 03。还需要注意的是InnoDB每行有隐藏列。同时可以看到,固定长度char字段在未填充满其长度时,会用0x20来进行填充。再来分析一下,记录头信息的最后4个字节代表next_recorder,0x1e00代表下一个记录的偏移量,当前记录的位置+0x1e00就是下一条记录的起始位置。所以InnoDB存储引擎在页内部是通过一种链表的结构来串联各个行记录的。

第二行我将不做整理,除了RowID不同外,它和第一行大同小异,有兴趣的读者可以用上面的方法自己试试。

现在我们关注有NULL值的第三行:

03 01          /*变长字段长度列表,逆序*/

06            /*NULL标志位,第三行有NULL值*/

00 00 20 ff 98       /*记录头信息*/

00 00 00 33 1e 02     /*RowID*/

00 00 00 81 51 2b    /*TransactionID*/

a2 00 00 01 48 01 10    /*Roll Pointer*/

64                  /*列1数据‘d‘*/

66 66 66        /*列4数据‘fff‘*/

第三行有NULL值,因此NULL标志位不再是00而是06了,转换成二进制为00000110,为1的值即代表了第2列和第3列的数据为NULL,在其后存储列数据的部分,我们会发现没有存储NULL,只存储了第1列和第4列非NULL的值。这个例子很好地说明了:不管是char还是varchar类型,NULL值是不占用存储空间的。

Redundant行记录格式

Redundant是MySQL 5.0版本之前InnoDB的行记录存储方式,MySQL 5.0支持Redundant是为了向前兼容性。Redundant行记录以如下方式存储:

从上图可以看到,不同于Compact行记录格式,Redundant行格式的首部是一个字段长度偏移列表,同样是按照列的顺序逆序放置的。当列的长度小于255字节,用1字节表示;若大于255个字节,用2个字节表示。第二个部分为记录头信息(record header),不同于Compact行格式,Redundant行格式固定占用6个字节(48位),每位的含义见表4-2。从表中可以看到,n_fields值代表一行中列的数量,占用10位,这也很好地解释了为什么MySQL一个行支持最多的列为1023。另一个需要注意的值为1byte_offs_flags,该值定义了偏移列表占用1个字节还是2个字节。最后的部分就是实际存储的每个列的数据了。

创建一张和mytest内容完全一样、但行格式为Redundant的表mytest2

wubx>create table mytest2 engine=innodb row_format=redundant as (select * from mytest);
Query OK, 3 rows affected (0.18 sec)
Records: 3  Duplicates: 0  Warnings: 0wubx>show table status like 'mytest2'\G
*************************** 1. row ***************************Name: mytest2Engine: InnoDBVersion: 10Row_format: RedundantRows: 3Avg_row_length: 5461Data_length: 16384
Max_data_length: 0Index_length: 0Data_free: 0Auto_increment: NULLCreate_time: 2017-08-19 19:52:08Update_time: NULLCheck_time: NULLCollation: latin1_swedish_ciChecksum: NULLCreate_options: row_format=REDUNDANTComment:
1 row in set (0.00 sec)wubx>select * from mytest;
+------+------+------+------+
| t1   | t2   | t3   | t4   |
+------+------+------+------+
| a    | bb   | bb   | ccc  |
| d    | ee   | ee   | fff  |
| d    | NULL | NULL | fff  |
+------+------+------+------+
3 rows in set (0.00 sec)

现在row_format变为Redundant。同样,通过hexdump将表空间mytest2.ibd导出到文本文件mytest2.txt。打开文件,找到类似如下行:

0000c070 08 03 00 00 73 75 70 72 65 6d 75 6d 00 23 20 16|……supremum.#.
0000c080 14 13 0c 06 00 00 10 0f 00 ba 00 00 00 2b 68 0b|……+h.
0000c090 00 00 00 00 06 53 80 00 00 00 32 01 10 61 62 62|……S……2..abb
0000c0a0 62 62 20 20 20 20 20 20 20 20 63 63 63 23 20 16|bb ccc#.
0000c0b0 14 13 0c 06 00 00 18 0f 00 ea 00 00 00 2b 68 0c|……+h.
0000c0c0 00 00 00 00 06 53 80 00 00 00 32 01 1e 64 65 65|……S……2..dee
0000c0d0 65 65 20 20 20 20 20 20 20 20 66 66 66 21 9e 94|ee fff!..
0000c0e0 14 13 0c 06 00 00 20 0f 00 74 00 00 00 2b 68 0d|……t……+h.
0000c0f0 00 00 00 00 06 53 80 00 00 00 32 01 2c 64 00 00|……S……2.,d..
0000c100 00 00 00 00 00 00 00 00 66 66 66 00 00 00 00 00|……fff……

整理可以得到如下内容:
23 20 16 14 13 0c 06/*长度偏移列表,逆序*/
00 00 10 0f 00 ba/*记录头信息,固定6个字节*/
00 00 00 2b 68 0b/*RowID*/
00 00 00 00 06 53/*TransactionID*/
80 00 00 00 32 01 10/*Roll Point*/
61/*列1数据‘a‘*/
62 62/*列2数据‘bb‘*/
62 62 20 20 20 20 20 20 20 20/*列3数据‘bb‘Char类型*/
63 63 63/*列4数据‘ccc‘*/

23 20 16 14 13 0c 06,逆转为06,0c,13,14,16,20,23。分别代表第一列长度6,第二列长度6(6+6=0x0C),第三列长度为7(6+6+7=0x13),第四列长度1(6+6+7+1=0x14),第五列长度2(6+6+7+1+2=0x16),第六列长度10(6+6+7+1+2+10=0x20),第七列长度3(6+6+7+1+2+10+3=0x23)。

记录头信息中应该注意48位中22~32位,为0000000111,表示表共有7个列(包含了隐藏的3列),接下去的33位为1,代表偏移列表为一个字节。

后面的信息就是实际每行存放的数据了,这与Compact行格式大致相同。

请注意是大致相同,因为如果我们来看第三行,会发现对于NULL的处理两者是不同的。

21 9e 94 14 13 0c 06/*长度偏移列表,逆序*/

00 00 20 0f 00 74/*记录头信息,固定6个字节*/

00 00 00 2b 68 0d/*RowID*/

00 00 00 00 06 53/*TransactionID*/

80 00 00 00 32 01 10/*Roll Point*/

64/*列1数据‘a‘*/

00 00 00 00 00 00 00 00 00 00/*列3数据NULL*/

66 66 66/*列4数据‘fff‘*/

这里与之前Compact行格式有着很大的不同了,首先来看长度偏移列表,我们逆序排列后得到06 0c 13 14 94 9e 21,前4个值都很好理解,第5个NULL变为了94,接着第6个列char类型的NULL值为9e(94+10=0x9e),之后的21代表14+3=0x21。可以看到对于varchar的NULL值,Redundant行格式同样不占用任何存储空间,因而char类型的NULL值需要占用空间。

当前表mytest2的字符集为Latin1,每个字符最多只占用1个字节。若这里将表mytest2的字符集转换为utf8,第三列char固定长度类型就不再是只占用10个字节了,而是10×3=30个字节,Redundant行格式下char固定字符类型将会占据可能存放的最大值字节数。

Compressed与Dynamic行记录格式

InnoDB Plugin引入了新的文件格式(file format,可以理解为新的页格式),对于以前支持的Compact和Redundant格式将其称为Antelope文件格式,新的文件格式称为Barracuda。Barracuda文件格式下拥有两种新的行记录格式Compressed和Dynamic两种。新的两种格式对于存放BLOB的数据采用了完全的行溢出的方式,在数据页中只存放20个字节的指针,实际的数据都存放在BLOB Page中,而之前的Compact和Redundant两种格式会存放768个前缀字节。

下图是Barracuda文件格式的溢出行:

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

转载于:https://www.cnblogs.com/ilifeilong/p/7396218.html

InnoDB存储引擎介绍-(6) 二. Innodb Antelope文件格式相关推荐

  1. MySQL技术内幕 InnoDB存储引擎——第2章 InnoDB存储引擎(未完待续)

    第2章 InnoDB存储引擎 2.1 InnoDB存储引擎概述 InnoDB存储引擎是第一个完整支持ACID事务的MySQL存储引擎(BDB是第一个支持事务的MySQL存储引擎,现在已经停止开发). ...

  2. InnoDB 存储引擎介绍

    1. MySQL 基础架构 前面写过几篇 MySQL 的文章,大多是对一些基础概念的讲解,当我想去了解存储引擎的时候发现不知从何下手,或者说不知道如何开头,回头想想好像对 MySQL 的基础架构还不是 ...

  3. mysql innodb 存储引擎

    --MySQL 结构有两部分组成 1.MySQL server 层 2.存储引擎层 --注:到 存储引擎层之前都属于 MySQL server 层 MySQL 5.1到 5.7 ,大版本 没有变化 , ...

  4. MySQL技术内幕-InnoDB存储引擎第2版-学习笔记-02

    MySQL技术内幕-InnoDB存储引擎第2版-学习笔记-02 6. 锁 ​ 人们认为行级锁总会增加开销.实际上,只有当实现本身会增加开销时,行级锁才会增加开销.InnoDB 存储引擎不需要锁升级,因 ...

  5. Mysql技术内幕——InnoDB存储引擎

    一.mysql体系结构和存储引擎 1.1.数据库和实例的区别 数据库:物理操作系统或其他形式文件类型的集合.在mysql下数据库文件可以是frm,myd,myi,ibd结尾的文件. 数据库实例:由数据 ...

  6. MySQL InnoDB存储引擎

    呵呵哒... MySQL体系结构和存储引擎 首先要搞懂的是什么是数据库,什么是数据库实例. 数据库:物理操作系统文件或其他形式文件类型的集合. 实例:MySQL数据库由后台线程以及一个共享内存区组成, ...

  7. 谈谈MySQL InnoDB存储引擎事务的ACID特性

    2019独角兽企业重金招聘Python工程师标准>>> 1.前言 狼哥一直对数据库Mysql这块没有进行过系统的深入学习,今天看到一篇文章写的还不错,特意分享一下,我不能保证文章中所 ...

  8. Mysql技术内幕InnoDB存储引擎——InnoDB存储引擎

    特此申明: 前段时间找工作所以看了<Mysql技术内幕InnoDB存储引擎>,整理的时候除了参考网上已有的笔记贴,加上自己整合的,可能和别人有雷同之处.不过无所谓啦,写出来自己看看,需要的 ...

  9. 数据库篇之InnoDB存储引擎

    文章目录 1. 数据库和实例 2. MySQL数据库 3. 存储引擎介绍 3.1 InnoDB 3.2 MyISAM 4. 连接数据库 5. InnoDB 存储引擎 5.1 后台线程 5.2 内存 1 ...

  10. 15.2. InnoDB存储引擎

    原贴:http://doc.mysql.cn/mysql5/refman-5.1-zh.html-chapter/storage-engines.html#innodb-overview 15.2.  ...

最新文章

  1. 一个项目中能提出哪些数据库优化_如何有效进行项目集管理?
  2. 策略模式和自定义排序规则
  3. Cognos8.3权限体系[转]
  4. 这是要把前几年积累的C++的节操给丢光吗
  5. wordpress中非插件统计文章浏览次数
  6. 从最小二乘到岭回归(Ridge Regression)的深刻理解
  7. python-第一个python程序-向世界问好
  8. 2021-06-13读写锁=独占锁与共享锁
  9. 毕马威深度解读北京自贸试验区方案
  10. pdf转word文档总结
  11. 计算机网络水晶头闪,网线水晶头坏了怎么办 小妙招一分钟解决你的问题
  12. 获取英雄联盟全皮肤(极速版)
  13. 天津2021高考成绩查询26号什么时间,2021年天津高考成绩26号几点可以查询,今天几点出高考成绩...
  14. 老男孩爬虫实战密训课第一季,2018.6,初识爬虫训练-实战2-自动登陆抽屉网
  15. XGBoost资料( 多届竞赛冠军获得者 周耀 整理)
  16. 计算机视觉算法面试准备
  17. 铁矿石大幅反弹,棉花认购大涨2倍,YP09继续探底2022.4.28
  18. tp3.2.3 图片打水印
  19. 【历史上的今天】12 月 30 日:C++ 之父诞生;Hotmail 创始人出生;Facebook 注册破百万
  20. 12.12下周黄金白银价格走势分析及期货原油操作建议布局

热门文章

  1. Flutter启动流程(Isolate机制+创建流程+线程练习)
  2. 贪心法LeetCode算法例子【总】
  3. Hadoop十年解读与发展预测
  4. pointnet-补充材料阅读
  5. 福建2021高考成绩查询是什么时间,2021年福建高考成绩排名及成绩公布时间什么时候出来...
  6. java实现pdf文件的电子签字+盖章+二维码+水印+PDF文件加密的解决方案
  7. 高保真设计软件介绍及推荐
  8. PHP实战项目(仿糯米网)
  9. 翻译: AWS DeepRacer一步一步详细步骤的自定义航点更快地运行 自定义waypoints
  10. 【程序员必备】七夕表白攻略:教你用代码轻松打动她的内心!