0


【MySQL InnoDB读书笔记】08 InnoDB下逻辑存储结构(一)

总体存储结构+行记录存储结构

一、索引组织表

在 InnoDB 存储引擎中,表中的数据都是根据

  1. 主键顺序

组织存放的,这种组织数据的方式的表称为

  1. 索引组织表

表主键的定义方式有以下三种:

  1. 显式定义一个非空属性为主键
  2. 若没有使用 1 定义主键,则首先判断表中是否有非空的唯一索引,若有则该列为主键
  3. 若 1 和 2 都没有满足,则 InnoDB 存储引擎自动创建一个 6 字节的指针,即 _rowid来作为主键

见示例:

  1. MySQL [gongruiyang]>createtable z(-> a intnotnull,-> b intnull,-> c intnotnull,-> d intnotnull,->uniquekey(b),->uniquekey(d),->uniquekey(c));
  2. Query OK,0rows affected (0.05 sec)
  3. MySQL [gongruiyang]>insertinto z select1,2,3,4;
  4. Query OK,1row affected (0.01 sec)
  5. Records: 1 Duplicates: 0Warnings: 0
  6. MySQL [gongruiyang]>insertinto z select5,6,7,8;
  7. Query OK,1row affected (0.01 sec)
  8. Records: 1 Duplicates: 0Warnings: 0
  9. MySQL [gongruiyang]>insertinto z select9,10,11,12;
  10. Query OK,1row affected (0.01 sec)
  11. Records: 1 Duplicates: 0Warnings: 0
  12. MySQL [gongruiyang]>select a,b,c,d,_rowid from z;+---+------+----+----+--------+| a | b | c | d | _rowid |+---+------+----+----+--------+|1|2|3|4|4||5|6|7|8|8||9|10|11|12|12|+---+------+----+----+--------+3rowsinset(0.01 sec)

  1. _rowid

的值我们可知:z 表的主键是 d

由于 b 是可为 null 的,所以不符合设置为主键的条件

属性 d 和属性 c 都是符合条件的,但是 d 比 c 先定义,故选择 d 作为主键

  1. _rowid

只能用来查看

  1. 单列主键

,对于

  1. 联合主键

就无能为力了

二、InnoDB 逻辑存储结构

在 InnoDB 存储引擎下,所有的数据都被逻辑的存放在表空间(tablespace)中,表空间又由各种段组成,段由区组成,区由页组成,页由行记录结构组成

image-20211223112559472

1. 表空间

  • 若没开启 innodb_file_per_table,则所有表的数据都放在共享表空间 ibdata1
  • 若开启 innodb_file_per_table,则每张表的数据、索引、insert buffer bitmap page放在独立的表空间内,其他数据(undo log page、insert buffer index page、double write buffer等)还是放在共享表空间 ibdata1

使用

  1. py_innodb_page_info.py

工具查看共享表空间中有哪些数据页:

  1. gongruiyang@gongruiyang:/david-mysql-tools/py_innodb_page_type$ python py_innodb_page_info.py ibdata1
  2. Total number of page: 4864:
  3. Insert Buffer Bitmap: 6
  4. System Page: 133
  5. Transaction system Page: 3
  6. Freshly Allocated Page: 4440
  7. Undo Log Page: 234
  8. File Segment inode: 11
  9. B-tree Node: 30
  10. File Space Header: 7

我们可以看到在

  1. 共享表空间 ibdata1

中,一共有 4864 个页:

undo log 页有 234 个

B-tree Node (数据)页有 30 个

2. 段

  1. 叶子节点段

即是

  1. 数据段

  1. 非叶子节点段

即是

  1. 索引段

,回滚段后续文章再续述,每个段由若干个区(Extend)组成,段的管理由 InnoDB 引擎完成。

3. 区

区是由连续的页组成的空间,每个区的大小恒为 1MB,一个区包含 64 个正常页,如果区内存的是压缩页,那么对应页大小为 2K、4K、8K 的页数量为 512 个、256个、128个,所以不论页的大小如何变化,区的大小恒不变

独立表空间的区大小变化:新建的表的表空间大小为 96 K(只有一个数据页) -> 刚开始的32个数据页是随着表中记录的增加而逐个增加的 -> 后续都每次表空间按照连续 64 个数据页的大小开始增长

独立表空间区变化图解:

image-20211223161523761

4. 页

页(Page)是 InnoDB 磁盘管理的最小单位,默认每个页大小为 16KB ,可通过参数

  1. innodb_page_size

来修改页大小

  1. MySQL [gongruiyang]>show variables like'innodb_page_size'\G;***************************1.row***************************
  2. Variable_name: innodb_page_size
  3. Value: 163841rowinset,1 warning (0.00 sec)

常见的页类型有:

  • 数据页(B-tree Node)
  • undo 页(undo log page)
  • 系统页(system page)
  • 插入缓冲位图页(insert buffer bitmap page)
  • 插入缓冲空闲列表页(insert buffer free list page)
  • 事务数据页(Transaction system page)
  • 未压缩的二进制大对象页(uncompressed BLOB page)
  • 压缩的二进制大对象页(compressed BLOB page)

5. 行记录

InnoDB 存储引擎是面向行(row - oriented)的,即数据是按照行进行存储的,每个页中存储的行记录的格式都是定义好的,最多允许存储(16KB / 2 - 200)行记录,即 7992 条行记录

三、InnoDB 行记录的格式

InnoDB 存储引擎提供了两种行记录的存储格式:

  1. Compact

  1. Redundant

  1. Compressed

  1. Dynamic

查看表的行记录存储格式方法:通过

  1. show table status like

来看

  1. Row_format

字段即可

  1. MySQL [gongruiyang]>showtablestatuslike't%'\G;***************************1.row***************************
  2. Name: t
  3. Engine: InnoDB
  4. Version: 10
  5. Row_format: Dynamic
  6. Rows: 4
  7. Avg_row_length: 4096
  8. Data_length: 16384
  9. Max_data_length: 0
  10. Index_length: 0
  11. Data_free: 0Auto_increment: NULL
  12. Create_time: 2021-12-2315:56:47
  13. Update_time: 2021-12-2315:59:17
  14. Check_time: NULL
  15. Collation: latin1_swedish_ci
  16. Checksum: NULL
  17. Create_options:
  18. Comment:
  19. ***************************2.row***************************
  20. Name: test
  21. Engine: InnoDB
  22. Version: 10
  23. Row_format: Dynamic
  24. Rows: 31
  25. Avg_row_length: 17441
  26. Data_length: 540672
  27. Max_data_length: 0
  28. Index_length: 0
  29. Data_free: 0Auto_increment: 65
  30. Create_time: 2021-12-2314:59:34
  31. Update_time: 2021-12-2315:42:36
  32. Check_time: NULL
  33. Collation: latin1_swedish_ci
  34. Checksum: NULL
  35. Create_options:
  36. Comment:
  37. 2rowsinset(0.00 sec)

1. Compact 行记录格式

Compact 行记录的格式如下图:

image-20211224110159734

  • 变长字段长度列表:该字段的长度是变化的,若列的长度小于 255 字节,用 1 字节表示,若列大于 255 字节,用 2 字节表示
  • NULL标志位:共 8 位,每一位表示当前列是否为 NULL,是 NULL 则当前位为 1
  • 头信息:占5字节,每一位的含义如下表
    名称大小(单位:位)含义()1未知()1未知deleted_flag1标记此行是否删除min_rec_flag1如果此行被预先定义为最小的记录,则设置为1n_owned4此行拥有的记录数heap_no13索引堆中该记录的排序记录record_type3记录类型,000表示普通,001表示B+树节点指针,010表示Infimum,011表示Supremum,1xx表示保留next_record16页中下一条记录的相对位置
    每行数据中除了用户定义的列外还有两个隐藏列:事务ID列(6字节)和回滚指针列(7字节),如果用户没有定义主键,可能还会多出来一个 rowid 列(6字节)

举例1:如果一个表使用

  1. row_format = compact

方式存储, 一共有四列(varchar(10) , varchar(10), char(10), varchar(10)),插入一条数据为(‘a’, NULL, ‘bb’, ‘ccc’)

则使用 Compact 行记录的格式存储在独立表空间中的数据为:

  1. NULL标志位

:0x02,二进制为 10,表示第二列为NULL值

  1. col1

:61(‘a’)

  1. col3

:62(‘b’) 62(‘b’) 20 20 20 20 20 20 20 20

  1. col4

:63(‘c’) 63(‘c’) 63(‘c’)

由此,我们可以观察到以下规律:

  1. 我们可以看出第三列为固定长度的char,如果该列中存储的数据没有达到固定长度,则剩余的字节使用 0x20 填充
  2. 无论是 char 还是 varchar 在 Compact 格式下存储 NULL 都不占用空间

2. Redundant 行记录格式

Redundant 行记录格式如下图:

image-20211224123813594

  • 字段长度偏移列表:同 Compact 的变长字段长度列表
  • 头信息:占 6 个字节,具体位信息如下表
    名称大小(单位:位)描述()1未知()1未知deleted_flag1标记此行是否已经被删除min_rec_flag1如果此行被预先定义为最小的记录,则设置为1n_owned4该记录拥有的记录数heap_no13索引堆中该条记录的索引号n_fields10记录中列的数量1byte_offs_flag1偏移列表为 1 字节还是 2 字节next_record16页中下一条记录的相对位置
    MySQL数据库一行支持最多的列个数由
    1. n_fields
    控制,即
    1. 2^10 -1 = 1023

我们发现:redundant 格式与 compact 格式不同的是没有

  1. NULL标志位

,可以看看下面例子中 redundant 格式是如何处理 NULL 列的

举例1:如果一个表使用

  1. row_format = redundant

方式存储, 一共有四列(varchar(10) , varchar(10), char(10), varchar(10)),插入一条数据为(‘d’, NULL, NULL, ‘fff’)

则使用 Redundant行记录的格式存储在独立表空间中的数据为:

  1. 字段长度偏移列表

:21 9e 94 14 13 0c 06

  1. col1

:64(‘d’)

  1. col3

:00 00 00 00 00 00 00 00 00 00

  1. col4

:66(‘f’) 66(‘f’) 66(‘f’)

由数据我们发现:

  1. 数据类型为 Char 的 NULL 列,会使用定义长度的个数个 0x00 来填充
  2. 数据类型为 varchar 的 NULL 列,则不存储

3. Compressed 行记录格式和 Dynamic 行记录格式

这两种行记录格式采用了

  1. 完全行溢出

的方式,B+ 数的叶子节点上面存储的是数据页,完全行溢出的方式是在数据页中存储 20 字节的指针,时间的数据都存放在

  1. Off Page

中,如图所示:

image-20211224144035646

四、不同数据类型的存储方式探究

1. varchar

MySQL 数据库的 varchar 类型可以存放

  1. 65532

  1. latin字符集编码

的字符,可以存放

  1. 21845

  1. utf8字符集编码

的字符,可以存放

  1. 32767

  1. gbk字符集编码

的字符,这里的的存储上限是指

  1. 所有的 varchar 类型的列之和

通过以下样例我们来看看 varchar 是如何存储的:

  1. 产生一个 65532大小的数据记录
  1. MySQL [gongruiyang]>createtable tt(-> a varchar(65532))engine=innodbcharset=latin1;
  2. Query OK,0rows affected (0.06 sec)
  3. MySQL [gongruiyang]>insertinto tt selectrepeat('a',65532);
  4. Query OK,1row affected (0.03 sec)
  5. Records: 1 Duplicates: 0Warnings: 0
  1. gongruiyang@gongruiyang:/mnt/e/宫瑞阳/计算机/GitHub开源项目/david-mysql-tools/py_innodb_page_type$ python py_innodb_page_info.py -v tt.ibd
  2. page offset 00000000, page type<File Space Header>
  3. page offset 00000001, page type<Insert Buffer Bitmap>
  4. page offset 00000002, page type<File Segment inode>
  5. page offset 00000003, page type<B-tree Node>, page level <0000>
  6. page offset 00000004, page type<Uncompressed BLOB Page>
  7. page offset 00000005, page type<Uncompressed BLOB Page>
  8. page offset 00000006, page type<Uncompressed BLOB Page>
  9. page offset 00000007, page type<Uncompressed BLOB Page>
  10. page offset 00000008, page type<Uncompressed BLOB Page>
  11. Total number of page: 9:
  12. Insert Buffer Bitmap: 1
  13. Uncompressed BLOB Page: 5
  14. File Space Header: 1
  15. B-tree Node: 1
  16. File Segment inode: 1

通过观察发现,只有一个数据页,但是多出来了 5 个

  1. Uncompressed BLOB Page(未压缩的二进制大对象页)
  1. 通过对页内数据分析发现数据页中只存放了这 65532 个字符的前 768 字节的前缀数据,剩下的(65532 - 768)个字节的数据存放在了 Uncompressed BLOB Page 中

image-20211224162140347

那是不是说,只要 varchar 中存储的数据大于 768 个字节,多余的字节就一定会存储的未压缩的二进制大对象页中?如果是这样的话,就会导致 B+ 树失去了意义(因为只有一个数据页,剩下数据就往二进制大对象页中插入就行),成为了一个链表。

如果一个数据页中恰好能放下两条记录,那么就不会把数据放到未压缩的二进制大对象页中去了,那么这个恰好放下两条记录的 varchar阈值 是多少呢?经过反复测试发现这个阈值为 8098 字节。

  • 实验一:设置 varchar 为8098
  1. MySQL [gongruiyang]>createtable tt(a varchar(8098))engine=innodbcharset=latin1;
  2. Query OK,0rows affected (0.05 sec)
  3. MySQL [gongruiyang]>insertinto tt selectrepeat('a',8098);
  4. Query OK,1row affected (0.02 sec)
  5. Records: 1 Duplicates: 0Warnings: 0
  6. MySQL [gongruiyang]>insertinto tt selectrepeat('a',8098);
  7. Query OK,1row affected (0.01 sec)
  8. Records: 1 Duplicates: 0Warnings: 0
  1. gongruiyang@gongruiyang:/mnt/e/宫瑞阳/计算机/GitHub开源项目/david-mysql-tools/py_innodb_page_type$ python py_innodb_page_info.py -v tt.ibd
  2. page offset 00000000, page type<File Space Header>
  3. page offset 00000001, page type<Insert Buffer Bitmap>
  4. page offset 00000002, page type<File Segment inode>
  5. page offset 00000003, page type<B-tree Node>, page level <0000>
  6. page offset 00000000, page type<Freshly Allocated Page>
  7. page offset 00000000, page type<Freshly Allocated Page>
  8. Total number of page: 6:
  9. Freshly Allocated Page: 2
  10. Insert Buffer Bitmap: 1
  11. File Space Header: 1
  12. B-tree Node: 1
  13. File Segment inode: 1

插入第三条数据:

  1. MySQL [gongruiyang]>insertinto tt selectrepeat('a',8098);
  2. Query OK,1row affected (0.01 sec)
  3. Records: 1 Duplicates: 0Warnings: 0
  1. gongruiyang@gongruiyang:/mnt/e/宫瑞阳/计算机/GitHub开源项目/david-mysql-tools/py_innodb_page_type$ python py_innodb_page_info.py -v tt.ibd
  2. page offset 00000000, page type<File Space Header>
  3. page offset 00000001, page type<Insert Buffer Bitmap>
  4. page offset 00000002, page type<File Segment inode>
  5. page offset 00000003, page type<B-tree Node>, page level <0001>
  6. page offset 00000004, page type<B-tree Node>, page level <0000>
  7. page offset 00000005, page type<B-tree Node>, page level <0000>
  8. Total number of page: 6:
  9. Insert Buffer Bitmap: 1
  10. File Space Header: 1
  11. B-tree Node: 3
  12. File Segment inode: 1

此时可以发现,插入两条数据时只有一个数据页,当插入第三条数据时出现了 B+ 树的分裂操作,产生了两个数据页

  • 实验二:设置 varchar 为8099
  1. MySQL [gongruiyang]>insertinto t selectrepeat('a',8099);
  2. Query OK,1row affected (0.01 sec)
  3. Records: 1 Duplicates: 0Warnings: 0
  1. gongruiyang@gongruiyang:/mnt/e/宫瑞阳/计算机/GitHub开源项目/david-mysql-tools/py_innodb_page_type$ python py_innodb_page_info.py -v t.ibd
  2. page offset 00000000, page type<File Space Header>
  3. page offset 00000001, page type<Insert Buffer Bitmap>
  4. page offset 00000002, page type<File Segment inode>
  5. page offset 00000003, page type<B-tree Node>, page level <0000>
  6. page offset 00000004, page type<Uncompressed BLOB Page>
  7. page offset 00000000, page type<Freshly Allocated Page>
  8. Total number of page: 6:
  9. Insert Buffer Bitmap: 1
  10. Freshly Allocated Page: 1
  11. File Segment inode: 1
  12. B-tree Node: 1
  13. File Space Header: 1
  14. Uncompressed BLOB Page: 1

才插入一条记录,就发现已经产生了 Uncompressed BLOB Page ,说明已经将部分数据插入到了 Uncompressed BLOB Page 中

总结:所以 varchar 的存储方式如图所示

image-20211224165214105

2. char

我们使用

  1. CHAR(N)

来定义一个存储 N 个字节定长字段,那么它真的只能存 N 个嘛?看以下实验:

定义一个 GBK 字符集编码的 char(2) 属性,并插入三条数据:ab、我们、a

  1. MySQL [gongruiyang]>createtable t(a char(2))engine=innodbcharset=GBK;
  2. Query OK,0rows affected (0.05 sec)
  3. MySQL [gongruiyang]>insertinto t select'ab';
  4. Query OK,1row affected (0.01 sec)
  5. Records: 1 Duplicates: 0Warnings: 0
  6. MySQL [gongruiyang]>insertinto t select'我们';
  7. Query OK,1row affected (0.01 sec)
  8. Records: 1 Duplicates: 0Warnings: 0
  9. MySQL [gongruiyang]>insertinto t select'a';
  10. Query OK,1row affected (0.01 sec)
  11. Records: 1 Duplicates: 0Warnings: 0
  12. MySQL [gongruiyang]>select a, CHAR_LENGTH(a), LENGTH(a)from t\G;***************************1.row***************************
  13. a: ab
  14. CHAR_LENGTH(a): 2
  15. LENGTH(a): 2***************************2.row***************************
  16. a: 我们
  17. CHAR_LENGTH(a): 2
  18. LENGTH(a): 4***************************3.row***************************
  19. a: a
  20. CHAR_LENGTH(a): 1
  21. LENGTH(a): 13rowsinset(0.00 sec)

我们发现:

‘ab’ 和 ‘我们’ 的长度都是 2,‘a’ 的长度是 1

实际上在内部存储上:‘ab’ 占 2 个字节, ''我们’占 4 个字节,'a’占 1 个字节

在 Compact/Redundant 行记录的格式中:如果 char(N) 中的并没有存够 N 个字符,则会使用 0x20 填充

总结:在多字节的字符编码中,char 类型不再代表固定长度的字符串,与 varchar 并没有什么区别,底层存储时都是按照变长对待的。

五、探究独立表空间大小变化过程

我们接下来来观察观察

  1. 独立表空间

的空间变化:

  1. 我们创建一个新的表:
  1. MySQL [gongruiyang]>createtable test(-> a intnotnullauto_increment,-> b varchar(7000),->primarykey(a)->)engine=innodb;
  2. Query OK,0rows affected (0.05 sec)
  1. 看看 test 表的独立表空间大小:
  1. gongruiyang@gongruiyang:/mnt/c/ProgramData/MySQL/MySQL Server 5.7/Data/gongruiyang$ ls -lh
  2. total 144K
  3. -rwxrwxrwx 1 gongruiyang gongruiyang 65 Dec 2214:53 db.opt
  4. -rwxrwxrwx 1 gongruiyang gongruiyang 13K Dec 2314:59 test.frm
  5. -rwxrwxrwx 1 gongruiyang gongruiyang 96K Dec 2314:59 test.ibd

发现刚刚建立的表的独立表空间大小为 96K

疑惑:不是说好的一个区的大小恒为 1M 吗?这个

  1. test.ibd

至少也应该是 1M 呀?

  1. 看看 test.ibd 中页的分配情况:
  1. gongruiyang@gongruiyang:/mnt/e/宫瑞阳/计算机/GitHub开源项目/david-mysql-tools/py_innodb_page_type$ python py_innodb_page_info.py -v test.ibd
  2. page offset 00000000, page type<File Space Header>
  3. page offset 00000001, page type<Insert Buffer Bitmap>
  4. page offset 00000002, page type<File Segment inode>
  5. page offset 00000003, page type<B-tree Node>, page level <0000>
  6. page offset 00000000, page type<Freshly Allocated Page>
  7. page offset 00000000, page type<Freshly Allocated Page>
  8. Total number of page: 6:
  9. Freshly Allocated Page: 2
  10. Insert Buffer Bitmap: 1
  11. File Space Header: 1
  12. B-tree Node: 1
  13. File Segment inode: 1

发现只分配一个一个数据页

  1. page offset 00000003, page type <B-tree Node>, page level <0000\>

,这里的<000>表示是叶子节点

  1. 插入两条记录看看页变化情况:
  1. MySQL [gongruiyang]>insert test selectNULL,REPEAT('a',7000);
  2. Query OK,1row affected (0.02 sec)
  3. Records: 1 Duplicates: 0Warnings: 0
  4. MySQL [gongruiyang]>insertinto test selectNULL,REPEAT('a',7000);
  5. Query OK,1row affected (0.01 sec)
  6. Records: 1 Duplicates: 0Warnings: 0
  1. gongruiyang@gongruiyang:/mnt/e/宫瑞阳/计算机/GitHub开源项目/david-mysql-tools/py_innodb_page_type$ python py_innodb_page_info.py -v test.ibd
  2. page offset 00000000, page type<File Space Header>
  3. page offset 00000001, page type<Insert Buffer Bitmap>
  4. page offset 00000002, page type<File Segment inode>
  5. page offset 00000003, page type<B-tree Node>, page level <0000>
  6. page offset 00000000, page type<Freshly Allocated Page>
  7. page offset 00000000, page type<Freshly Allocated Page>
  8. Total number of page: 6:
  9. Freshly Allocated Page: 2
  10. Insert Buffer Bitmap: 1
  11. File Space Header: 1
  12. B-tree Node: 1
  13. File Segment inode: 1

据观察,插入两条数据后,页的分配并无任何变化,依然是只有一个数据页

  1. 再插入一条记录观察页变化情况
  1. MySQL [gongruiyang]>insertinto test selectNULL,REPEAT('a',7000);
  2. Query OK,1row affected (0.01 sec)
  3. Records: 1 Duplicates: 0Warnings: 0
  4. MySQL [gongruiyang]>select a from test\G;***************************1.row***************************
  5. a: 1***************************2.row***************************
  6. a: 2***************************3.row***************************
  7. a: 33rowsinset(0.00 sec)
  1. gongruiyang@gongruiyang:/mnt/e/宫瑞阳/计算机/GitHub开源项目/david-mysql-tools/py_innodb_page_type$ python py_innodb_page_info.py -v test.ibd
  2. page offset 00000000, page type<File Space Header>
  3. page offset 00000001, page type<Insert Buffer Bitmap>
  4. page offset 00000002, page type<File Segment inode>
  5. page offset 00000003, page type<B-tree Node>, page level <0001>
  6. page offset 00000004, page type<B-tree Node>, page level <0000>
  7. page offset 00000005, page type<B-tree Node>, page level <0000>
  8. Total number of page: 6:
  9. Insert Buffer Bitmap: 1
  10. File Space Header: 1
  11. B-tree Node: 3
  12. File Segment inode: 1

<000>表示叶子节点,**<001>表示非叶子节点**,再插入一条新的数据后产生了 B+ 数的分裂操作

此时 B+ 树的结构如下:共有两个叶子节点<000>,一个非叶子节点<001>image-20211223152220370由此可以看出,每两条记录就占据一个数据页

  1. 我们一直增加到 63 条记录看看变化情况:
  1. MySQL [gongruiyang]>delimiter $$
  2. MySQL [gongruiyang]>createprocedure load_test(count int)->BEGIN->declare s intdefault1;->declare c varchar(7000)defaultrepeat('a',7000);->while s <= count do->insertinto test selectNULL, c;->set s = s +1;->endwhile;->END;-> $$
  3. Query OK,0rows affected (0.01 sec)
  4. MySQL [gongruiyang]>delimiter;
  5. MySQL [gongruiyang]>call load_test(60);
  6. Query OK,1row affected (0.55 sec)
  7. MySQL [gongruiyang]>selectcount(*)from test\G;***************************1.row***************************count(*): 631rowinset(0.00 sec)

使用存储过程再插入 60 条记录,此时有 63 条数据,我们再看看独立表空间变化情况:

  1. gongruiyang@gongruiyang:/mnt/c/ProgramData/MySQL/MySQL Server 5.7/Data/gongruiyang$ ls -lh
  2. total 656K
  3. -rwxrwxrwx 1 gongruiyang gongruiyang 65 Dec 2214:53 db.opt
  4. -rwxrwxrwx 1 gongruiyang gongruiyang 13K Dec 2314:59 test.frm
  5. -rwxrwxrwx 1 gongruiyang gongruiyang 592K Dec 2315:34 test.ibd
  6. gongruiyang@gongruiyang:/mnt/e/宫瑞阳/计算机/GitHub开源项目/david-mysql-tools/py_innodb_page_type$ python py_innodb_page_info.py -v test.ibd
  7. page offset 00000000, page type<File Space Header>
  8. page offset 00000001, page type<Insert Buffer Bitmap>
  9. page offset 00000002, page type<File Segment inode>
  10. page offset 00000003, page type<B-tree Node>, page level <0001>
  11. page offset 00000004, page type<B-tree Node>, page level <0000>
  12. page offset 00000005, page type<B-tree Node>, page level <0000>
  13. page offset 00000006, page type<B-tree Node>, page level <0000>
  14. page offset 00000007, page type<B-tree Node>, page level <0000>
  15. page offset 00000008, page type<B-tree Node>, page level <0000>
  16. page offset 00000009, page type<B-tree Node>, page level <0000>
  17. page offset 0000000a, page type<B-tree Node>, page level <0000>
  18. page offset 0000000b, page type<B-tree Node>, page level <0000>
  19. page offset 0000000c, page type<B-tree Node>, page level <0000>
  20. page offset 0000000d, page type<B-tree Node>, page level <0000>
  21. page offset 0000000e, page type<B-tree Node>, page level <0000>
  22. page offset 0000000f, page type<B-tree Node>, page level <0000>
  23. page offset 00000010, page type<B-tree Node>, page level <0000>
  24. page offset 00000011, page type<B-tree Node>, page level <0000>
  25. page offset 00000012, page type<B-tree Node>, page level <0000>
  26. page offset 00000013, page type<B-tree Node>, page level <0000>
  27. page offset 00000014, page type<B-tree Node>, page level <0000>
  28. page offset 00000015, page type<B-tree Node>, page level <0000>
  29. page offset 00000016, page type<B-tree Node>, page level <0000>
  30. page offset 00000017, page type<B-tree Node>, page level <0000>
  31. page offset 00000018, page type<B-tree Node>, page level <0000>
  32. page offset 00000019, page type<B-tree Node>, page level <0000>
  33. page offset 0000001a, page type<B-tree Node>, page level <0000>
  34. page offset 0000001b, page type<B-tree Node>, page level <0000>
  35. page offset 0000001c, page type<B-tree Node>, page level <0000>
  36. page offset 0000001d, page type<B-tree Node>, page level <0000>
  37. page offset 0000001e, page type<B-tree Node>, page level <0000>
  38. page offset 0000001f, page type<B-tree Node>, page level <0000>
  39. page offset 00000020, page type<B-tree Node>, page level <0000>
  40. page offset 00000021, page type<B-tree Node>, page level <0000>
  41. page offset 00000022, page type<B-tree Node>, page level <0000>
  42. page offset 00000023, page type<B-tree Node>, page level <0000>
  43. page offset 00000000, page type<Freshly Allocated Page>
  44. Total number of page: 37:
  45. Freshly Allocated Page: 1
  46. Insert Buffer Bitmap: 1
  47. File Space Header: 1
  48. B-tree Node: 33
  49. File Segment inode: 1

此时

  1. test.ibd

大小为 592K ,依然小于 1M ,其中 B-tree Node 一共是 33 个,包含 1 个非叶节点页和 32 个叶节点页,对于数据段来说,此时已经有了 32 个数据页了

  1. 我们再插入一条数据,注意观察变化:
  1. MySQL [gongruiyang]>insertinto test selectNULL,REPEAT('a',7000);
  2. Query OK,1row affected (0.03 sec)
  3. Records: 1 Duplicates: 0Warnings: 0
  1. gongruiyang@gongruiyang:/mnt/c/ProgramData/MySQL/MySQL Server 5.7/Data/gongruiyang$ ls -lh
  2. total 2.1M
  3. -rwxrwxrwx 1 gongruiyang gongruiyang 65 Dec 2214:53 db.opt
  4. -rwxrwxrwx 1 gongruiyang gongruiyang 13K Dec 2314:59 test.frm
  5. -rwxrwxrwx 1 gongruiyang gongruiyang 2.0M Dec 2315:42 test.ibd
  6. gongruiyang@gongruiyang:/mnt/e/宫瑞阳/计算机/GitHub开源项目/david-mysql-tools/py_innodb_page_type$ python py_innodb_page_info.py test.ibd
  7. Total number of page: 128:
  8. Freshly Allocated Page: 91
  9. Insert Buffer Bitmap: 1
  10. File Space Header: 1
  11. B-tree Node: 34
  12. File Segment inode: 1

此时 test 表的独立表空间文件大小已经变成了 2M 的大小,所以此时应该是申请了(32 + 64)个数据页以供使用


本文转载自: https://blog.csdn.net/weixin_45437022/article/details/122133125
版权归原作者 代码被吃掉了 所有, 如有侵权,请联系我们删除。

“【MySQL InnoDB读书笔记】08 InnoDB下逻辑存储结构(一)”的评论:

还没有评论