写点什么

[翻译] 使用 innodb_ruby 探索 InnoDB 的页面管理

用户头像
keaper
关注
发布于: 4 小时前
[翻译] 使用 innodb_ruby 探索 InnoDB 的页面管理

本系列文章翻译自 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-regionsstart       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-listsname                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-iteratestart_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-indexesid          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-listsname                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-pagespage        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,165INDEX 类型的页面:


$ innodb_space -f test/t.ibd space-page-type-regionsstart       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-listsname                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-iterate2560        ................................................................2624        ................................................................
复制代码


free_frag 区段描述符链表中的区段有一些“碎片”页面被使用:


$ innodb_space -f test/t.ibd -L free_frag space-list-iteratestart_page  page_used_bitmap                                                0           ######################################..........................
复制代码


通过 space-indexes 命令可以看出大量已使用的页面被分配给叶文件段,也正如预期的一样,只有3个“内部”页面来管理 b+树 中的2,162个(译者注:原文为2,137,但结合下文输出应该为2,162)“叶”页面:


$ innodb_space -f test/t.ibd space-indexesid          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-listsname                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-pagespage        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 区段和 6not_full 区段:


$ innodb_space -f test/t.ibd -p 3 index-fseg-leaf-listsname                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-pagespage        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-iteratestart_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-iteratestart_page  page_used_bitmap                                                2176        #############...................................................2240        #...............................................................2304        #...............................................................2368        #...............................................................2432        #...............................................................2496        #...............................................................
复制代码


你可以在这里看到 InnoDB 页面拆分优化的一点“影子”: 为了在磁盘上按顺序排列数据, InnoDB 多次从 free 区段的第一个页面分配页面(页码是最可疑之处)。未来我们将对这种行为进行更深入的研究。


译者注:这里的“可疑之处”指的是上述 not_full 区段链表的 start_page 之间的间隔都是相同的 64。

发布于: 4 小时前阅读数: 7
用户头像

keaper

关注

还未添加个人签名 2018.01.19 加入

还未添加个人简介

评论

发布
暂无评论
[翻译] 使用 innodb_ruby 探索 InnoDB 的页面管理