19. 行记录
页的结构
File Header
记录
ROW_FORMAT
- REDUDENT:兼容老版本的InnoDB,MySQL 4.1版本之前
- COMPACT:MySQL 5.6 版本的默认格式
- COMPRESSED:支持压缩
- DYNAMIC:大对象记录优化,MySQL 5.7 版本默认格式
COMPACT 结构
- variable string length list
- 变长字段列表,表示有多少个变长字段,且序号逆序显示
- NULL flag
- 是否有NULL值
- rowid
- B+树索引键值
- trx id
- 事物ID,6个字节
- roll pointer
- 回滚指针,7个字节
- char 和 varchar 的区别
详细区别可以看之前的数据类型
结果:
在 多字节字符集 (如UTF8mb4)下:
- char(N) 中存储的数据的长度 范围 是 N ~ 4N ,当存储数据的长度 M , 未达到N 时,则填充空格(0x20),且空格的长度 取最小 的长度 N-M ,而 不是4N-M
- varchar(N) 则 不填充空格
注意: char 数据类型本来是定长数据,但是在多字节字符集下,表现的行为和varchar类似,失去了原来的优势,当数据更新变长后可能无法原地更新
- 原地更新
-
- 原地更新不会占用新的存储空间
- 非原地更新需要删除(物理删除)原来的空间的数据,然后将更新后的数据插入到页的后面
- 删除的数据的空间,会插入到 Free_List 链表的头部
- 原地更新不会触发页的分裂
Free_List 是将页中被删除的空间串联在一起(组成一个链表 ),当有数据被插到页内时,先看一下Free_list中第一个空间的大小,如果空间合适,就将该记录插入到第一个空间中去,如果不合适,直接插入到页的尾部的剩余空间。( 不会去看Free_list的第二个空间 )。当该页的数据被插满了,不会马上进行分页,而是进行 reorganize 操作,即将页内的数据在内存中进行整理,然后覆盖原来的页(不影响性能)。所以InnoDB不需要碎片整理。
- Reorganize
DYNAMIC
DYNAMIC相比COMPACT,优化了大对象记录的存储。
假设有一条记录有A,B,C,D 四列,其中D列的是text类型,且含有2W个字节的长度。
- COMPACT
COMPACT会存储text中的前768个字节的数据,剩余的数据通过20个字节的指针指向溢出页
- DYNAMIC
DYNAMIC直接通过20个字节的指针指向溢出页
相对COMPACT,DYNAMIC在一个页中存储的 记录数 更多(因为有768字节的prefix,一条记录的字节假设是800字节,那16K的页只能存放20条记录,而我测算可以存放80条记录),这样一来,B+树的高度可能会变高,读取的IO次数可能会变多。
一个页能存放的记录越多,则性能越优
heap number
- heap number表示页中每个记录插入的顺序序号
- 假设插入的数据是a, b, c, d, e, g;则对应的heap number是 2, 3, 4, 5, 6
- 0和1被infimum和supermum所使用
- infimum对应最小的heap_number
- supermum对应最大的heap_number,随着数据的插入,该值会更新
- update对heap_number没有影响
- heap_number是物理的,存储在row的 record_header 字段中
例子
-- 终端1
root@mysqldb 13:34: [gavin]> create table test_heap(a int primary key);
Query OK, 0 rows affected (3.01 sec)
root@mysqldb 13:35: [gavin]> insert into test_heap values (1);
Query OK, 1 row affected (0.02 sec)
root@mysqldb 13:35: [gavin]> begin;
Query OK, 0 rows affected (0.00 sec)
root@mysqldb 13:35: [gavin]> delete from test_heap where a=1;
Query OK, 1 row affected (0.00 sec)
root@mysqldb 13:35: [gavin]> show variables like "%innodb_status_output_locks%";
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| innodb_status_output_locks | OFF |
+----------------------------+-------+
1 row in set (0.00 sec)
root@mysqldb 13:35: [gavin]> set global innodb_status_output_locks=1; -- 打印详细锁信息
-- 终端2
root@mysqldb 13:34: [(none)]> pager less -- 使用类似linux中的less命令方式进行查看,可上下翻页
PAGER set to 'less'
root@mysqldb 14:01: [(none)]> show engine innodb status\G
-- 省略其他输出
2 lock struct(s), heap size 1128, 1 row lock(s), undo log entries 1
MySQL thread id 8, OS thread handle 140402550052416, query id 36 localhost root
TABLE LOCK table `gavin`.`test_heap` trx id 18469 lock mode IX
RECORD LOCKS space id 29 page no 4 n bits 72 index PRIMARY of table `gavin`.`test_heap` trx id 18469 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 32
0: len 4; hex 80000001; asc ;; -- 插入的主键a=1
1: len 6; hex 000000004825; asc H%;; 0x4825的十进制就是18469,表示事务id
2: len 7; hex 02000001500b9b; asc P ;; -- roll pointer(回滚指针)
-- 省略其他输出
-- space id 29
-- page no 4
-- heap no 2
root@mysqldb 14:01: [gavin]> rollback;
Query OK, 0 rows affected (0.00 sec)
-- heap no = 1 的一种情况
-- 终端1
root@mysqldb 14:05: [gavin]> set transaction_isolation='repeatable-read';
Query OK, 0 rows affected (0.00 sec)
root@mysqldb 14:06: [gavin]> begin;
Query OK, 0 rows affected (0.00 sec)
root@mysqldb 14:06: [gavin]> select * from test_heap where a>1 for update;
Empty set (0.00 sec)
-- 终端2
root@mysqldb 14:01: [(none)]> show engine innodb status\G
-- 省略其他输出
---TRANSACTION 18472, ACTIVE 5 sec -- 事务活跃了5s
2 lock struct(s), heap size 1128, 2 row lock(s)
MySQL thread id 8, OS thread handle 140402550052416, query id 42 localhost root
TABLE LOCK table `gavin`.`test_heap` trx id 18472 lock mode IX
RECORD LOCKS space id 29 page no 4 n bits 72 index PRIMARY of table `gavin`.`test_heap` trx id 18472 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;; -- 一条伪记录
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 4; hex 80000001; asc ;;
1: len 6; hex 000000004818; asc H ;;
2: len 7; hex 820000014d0110; asc M ;;
-- 省略其他输出