本系列文章翻译自 Jeremy Cole's Blog 中的 InnoDB系列 文章 。共 16 篇,本文为第 5 篇。原文链接:Exploring InnoDB page management with innodb_ruby
因翻译水品有限,为了避免对读者造成误解,一些专有名词的翻译会在其后用[]
标记出原文。
使用 innodb_ruby 探索 InnoDB 的页面管理
[本文中所使用的 innodb_ruby
版本为 0.8.8(发布于2014年2月3日)]
在 On learning InnoDB: A journey to the core (译文)一文中,我提到了 innodb_ruby 项目以及其中的命令行工具。在后续 A quick introduction to innodb_ruby(译文)一文中,我介绍了 innodb_space
命令行工具的安装和一些快速演示。
在上一篇文章 Page management in InnoDB space files(译文)中,我描述了 InnoDB
的区段、文件段以及空闲空间管理相关的结构。接下来,我会提供一些使用 innodb_space
检查真实的表中这些结构的示例。
一个最小化的空表
我创建了一个空表(表结构不重要)来说明 InnoDB
页面管理结构的“最小化”状态。space-page-type-regions
命令会汇总出同一类型页面的所有连续区域:
$ innodb_space -f test/e.ibd space-page-type-regions
start end count type
0 0 1 FSP_HDR
1 1 1 IBUF_BITMAP
2 2 1 INODE
3 3 1 INDEX
4 5 2 FREE (ALLOCATED)
复制代码
通过输出可以看到,这张表已经在 .idb
文件中分配了“标准”页面: FSP_HDR
页面、IBUF_BITMAP
页面、INODE
页面、INDEX
页面(用于空索引的根),还有两个未使用的 FREE (ALLOCATED)
页面 。
space-lists
命令会汇总空间中的区段描述符链表和 inode
链表:
$ innodb_space -f test/e.ibd space-lists
name length f_page f_offset l_page l_offset
free 0 0 0 0 0
free_frag 1 0 158 0 158
full_frag 0 0 0 0 0
full_inodes 0 0 0 0 0
free_inodes 1 2 38 2 38
复制代码
只有 free_frag
区段描述符链表中有条目,并且其中只有一个区段。free_inodes
链表中有一个 INODE
页面。
可以使用 space-list-iterate
命令检查 free_frag
链表的内容,该命令将打印一个图形,说明在区段列表中所有区段内页面的使用情况("#"
表示该页面已使用,"."
表示页面是空闲的) :
$ innodb_space -f test/e.ibd -L free_frag space-list-iterate
start_page page_used_bitmap
0 ####............................................................
复制代码
译者注:实际上由上文的 space-page-type-regions
命令输出可以看出,InnoDB
目前只分配了6
个页面,space-list-iterate
的输出中第一个区段中不应该有64
个#
或者.
。如果你使用最新版本的innodb_ruby
运行上述命令会发现,只会输出####..
,表示有 4 个页面已使用,2 个页面未使用。
space-indexes
可以将空间中所有索引的文件段进行汇总:
$ innodb_space -f test/e.ibd space-indexes
id root fseg used allocated fill_factor
16 3 internal 1 1 100.00%
16 3 leaf 0 0 0.00%
复制代码
只有“内部”文件段分配了页面,并且只分配了一个页面。index-fseg-internal-lists
模式将汇总“内部”文件段中的区段链表:
$ innodb_space -f test/e.ibd -p 3 index-fseg-internal-lists
name length f_page f_offset l_page l_offset
free 0 0 0 0 0
not_full 0 0 0 0 0
full 0 0 0 0 0
复制代码
这三个列表都是空的,因为这个空表没有分配任何完整的区段。那么,已使用的一个页面在哪里呢?这是一个“碎片”页面,可以使用 index-fseg-internal-frag-pages
模式列出:
$ innodb_space -f test/e.ibd -p 3 index-fseg-internal-frag-pages
page index level data free records
3 16 0 0 16252 0
复制代码
这是表的“最小化”状态———空间文件中大部分是空白的簿记[bookeeping
]结构,只有一个 INDEX
页面。接下来让我们来看一个包含一些实际数据的表。
一个有一百万行的表
在 A quick introduction to innodb_ruby (译文)一文中,我创建了一个包含 100万
行的表。我们将在下文的示例中使用相同的表。
通过 space-page-type-regions
命令可以看到总共有 2,165
个 INDEX
类型的页面:
$ innodb_space -f test/t.ibd space-page-type-regions
start end count type
3 37 35 INDEX
38 63 26 FREE (ALLOCATED)
64 2188 2125 INDEX
2189 2239 51 FREE (ALLOCATED)
2240 2240 1 INDEX
2241 2303 63 FREE (ALLOCATED)
2304 2304 1 INDEX
2305 2367 63 FREE (ALLOCATED)
2368 2368 1 INDEX
2369 2431 63 FREE (ALLOCATED)
2432 2432 1 INDEX
2433 2495 63 FREE (ALLOCATED)
2496 2496 1 INDEX
2497 2687 191 FREE (ALLOCATED)
复制代码
译者注:上面的输出只展示了 INDEX
类型和 FREE (ALLOCATED)
类型的页面,如果你实际执行这个命令,应该还会输出其他类型的页面,比如 FSP_HDR
页面、IBUF_BITMAP
页面、INODE
页面。
注意,在 INDEX
页面的连续区域中间有一些 FREE (ALLOCATED)
页面组成的间隙。这是因为InnoDB
不能保证按顺序使用空闲页面,而且有关批量数据加载的许多优化也会导致页面无序使用。(更多关于页面拆分和这些优化的内容将在以后的文章中介绍)
再来看看看空间中的链表,有一些区段在 free
链表中,也有一些区段在 free_frag
链表中:
$ innodb_space -f test/t.ibd space-lists
name length f_page f_offset l_page l_offset
free 2 0 1758 0 1798
free_frag 1 0 158 0 158
full_frag 0 0 0 0 0
full_inodes 0 0 0 0 0
free_inodes 1 2 38 2 38
复制代码
如预期的一样,free
区段描述符链表中的区段 所有页面都是空闲的:
$ innodb_space -f test/t.ibd -L free space-list-iterate
2560 ................................................................
2624 ................................................................
复制代码
free_frag
区段描述符链表中的区段有一些“碎片”页面被使用:
$ innodb_space -f test/t.ibd -L free_frag space-list-iterate
start_page page_used_bitmap
0 ######################################..........................
复制代码
通过 space-indexes
命令可以看出大量已使用的页面被分配给叶文件段,也正如预期的一样,只有3
个“内部”页面来管理 b+树
中的2,162
个(译者注:原文为2,137
,但结合下文输出应该为2,162
)“叶”页面:
$ innodb_space -f test/t.ibd space-indexes
id root fseg used allocated fill_factor
15 3 internal 3 3 100.00%
15 3 leaf 2162 2528 85.52%
复制代码
你还可以看到叶文件段分配的页面比实际使用的多,fill_factor
(“填充因子”)为 85.52%
。这是由于 InnoDB
的 段填充因子[segment fill factor
] 在 MySQL
中固定为 87.5%
。不过现在在 Twitter MySQL 中是可以进行配置的,这要归功于 Facebook
提交的 MySQL Bug 64673。
因为内部文件段只有 3
个页面,所以文件段列表都是空的:
$ innodb_space -f test/t.ibd -p 3 index-fseg-internal-lists
name length f_page f_offset l_page l_offset
free 0 0 0 0 0
not_full 0 0 0 0 0
full 0 0 0 0 0
复制代码
3
个已使用的页面被分配为碎片页:
$ innodb_space -f test/t.ibd -p 3 index-fseg-internal-frag-pages
page index level data free records
3 15 2 26 16226 2
36 15 1 14521 1401 1117
37 15 1 13585 2341 1045
复制代码
而叶子索引文件段的链表则非常“繁忙”,有 33
(译者注:原文这里为32
,结合下文输出,应为33
)个 full
区段和 6
个 not_full
区段:
$ innodb_space -f test/t.ibd -p 3 index-fseg-leaf-lists
name length f_page f_offset l_page l_offset
free 0 0 0 0 0
not_full 6 0 1518 0 1718
full 33 0 198 0 1478
复制代码
此外,叶文件段已经分配了所有可以分配的 32
个碎片页面(在分配完整区段之前会先分配碎片页面):
$ innodb_space -f test/t.ibd -p 3 index-fseg-leaf-frag-pages
page index level data free records
4 15 0 9812 6286 446
5 15 0 15158 860 689
6 15 0 10912 5170 496
7 15 0 10670 5412 485
8 15 0 12980 3066 590
9 15 0 11264 4808 512
10 15 0 4488 11690 204
11 15 0 9680 6418 440
12 15 0 9306 6800 423
13 15 0 9658 6434 439
14 15 0 10032 6062 456
15 15 0 9988 6108 454
16 15 0 9570 6530 435
17 15 0 9130 6978 415
18 15 0 8844 7266 402
19 15 0 11770 4300 535
20 15 0 9020 7092 410
21 15 0 8646 7462 393
22 15 0 9746 6354 443
23 15 0 11066 5014 503
24 15 0 8910 7204 405
25 15 0 11748 4322 534
26 15 0 10978 5094 499
27 15 0 11132 4940 506
28 15 0 9350 6750 425
29 15 0 13508 2526 614
30 15 0 14938 1082 679
31 15 0 14520 1506 660
32 15 0 9086 7016 413
33 15 0 9724 6368 442
34 15 0 10978 5102 499
35 15 0 9504 6592 432
复制代码
正如预期的那样,full
区段都是“满”的:
$ innodb_space -f test/t.ibd -p 3 -L full index-fseg-leaf-list-iterate
start_page page_used_bitmap
64 ################################################################
128 ################################################################
192 ################################################################
256 ################################################################
320 ################################################################
384 ################################################################
448 ################################################################
512 ################################################################
576 ################################################################
640 ################################################################
704 ################################################################
768 ################################################################
832 ################################################################
896 ################################################################
960 ################################################################
1024 ################################################################
1088 ################################################################
1152 ################################################################
1216 ################################################################
1280 ################################################################
1344 ################################################################
1408 ################################################################
1472 ################################################################
1536 ################################################################
1600 ################################################################
1664 ################################################################
1728 ################################################################
1792 ################################################################
1856 ################################################################
1920 ################################################################
1984 ################################################################
2048 ################################################################
2112 ################################################################
复制代码
not_full
区段都是部分空闲的,正如预期的那样:
$ innodb_space -f test/t.ibd -p 3 -L not_full index-fseg-leaf-list-iterate
start_page page_used_bitmap
2176 #############...................................................
2240 #...............................................................
2304 #...............................................................
2368 #...............................................................
2432 #...............................................................
2496 #...............................................................
复制代码
你可以在这里看到 InnoDB
页面拆分优化的一点“影子”: 为了在磁盘上按顺序排列数据, InnoDB
多次从 free
区段的第一个页面分配页面(页码是最可疑之处)。未来我们将对这种行为进行更深入的研究。
译者注:这里的“可疑之处”指的是上述 not_full
区段链表的 start_page
之间的间隔都是相同的 64。
评论