innodb_ruby 项目简介
本系列文章翻译自 Jeremy Cole's Blog 中的 InnoDB系列 文章 。共 16 篇,本文为第 2 篇。原文链接:A quick introduction to innodb_ruby
因翻译水平有限,为了避免对读者造成误解,一些专有名词的翻译会在其后用
[]
标记出原文。
innodb_ruby 项目简介
本文中所使用的 `innodb_ruby` 版本为 [0.8.8(发布于2014年2月3日)]
在 On learning InnoDB: A journey to the core(译文)一文中,我提到了 innodb_ruby
项目。现在我来演示一下它的一些功能。我不会去解释所有提及的 InnoDB
结构,这不是本文的初衷,后面的文章中会继续介绍这些结构!
安装 innodb_ruby
如果你熟悉 Ruby
和 gems
,并且已经安装并配置好了 Ruby
环境,那么你只需要执行如下命令即可完成安装(因为我经常将 innodb_ruby
gems
推送到 RubyGems
,所以可以直接使用 gem install
命令完成安装):
译者注:
RubyGems
是Ruby
的一个包管理框架,类似于Python
中的pip
。RubyGems
管理的包称为gems
,同时RubyGems
有一个公共的存储库 rubygems.org 供开发人员使用。
如果这个方法不起作用,那么你可能需要查看 RubyGems文档 来帮助你完成安装。或者就此放弃一切希望。:-D
当你成功安装了 innodb_ruby
,在你的 path
下应该有一个 innodb_space
命令:
生成一些数据
为了进行演示,我们需要创建更多的记录以便检查不同的数据结构。首先需要确保你运行了一个版本足够新的 MySQL Server
(MySQL 5.5
或者更新的版本),使用 Barrracuda
格式的表,并且启用了 innodb_file_per_table
(译者注:通过innodb_file_per_table
启动参数来开启)。使用下面这一段 ruby
代码可以创建一个非常简单的表并填充一些数据:
执行这段代码将会生成一个包含100万
行数据的表(为了让事情更有趣,我们将这些数据是按照随机的顺序插入),大约48MB
,也就是大约3,071
个大小为16KB
的页面。
译者注:执行上述代码需要安装
mysql
的gem
。如果通过gem install mysql
安装失败,可以尝试使用gem install mysql2
来安装mysql2
来操作MySQL
,并且需要对代码进行如下改写:
(请注意,如果你自己尝试使用上面的方法来新建数据,你应该通过SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty'
命令观察并等待所有脏页刷新完成后再继续,因为下面介绍的工具将要访问的是磁盘上的表空间文件,与运行中的 InnoDB
实例中的数据并不完全一致。)
译者注:Innodb_buffer_pool_pages_dirty 状态变量表示
InnoDB
缓冲池[buffer pool
]中的当前的脏页数量。该状态变量的值为0
则表示所有的脏页已经刷新到磁盘。
检查表空间文件
innodb_space
中的space-page-type-regions
命令能够提供对表空间文件的最高级别概览,它会将相同类型的连续页面打印为一行:
先不必深究 InnoDB
内部实现细节,你可以看到 一些 InnoDB
的簿记[bookkeeping
]结构(FSP_HDR
页、 IBUF_BITMAP
页 和 INODE
页)、实际的表数据(INDEX
页)和空闲空间(FREE (ALLOCATED)
页)。
每个索引(实际上是每个“文件段” 或 每个索引对应的“文件段”)所消耗的空间也很有趣(输出中的 used
和 allocated
是以页为单位的):
每个索引都有一个 “内部[internal]
”文件段(用于非叶子结点页面)和一个“叶[leaf]
”文件段(用于叶子结点页面)。页面可能被分配给一个文件段,但是当前还未使用(也就是类型为 FREE (ALLOCATED)
的页面),"fill_factor"
列表示的是使用的页面和未使用的页面的比率。(请注意,这个比率与索引页 有多满 没有关系,那完全是另外一回事。)
译者注:这里说的索引有多满指的是索引树上页面的饱和度,删除记录或者添加记录导致的页分裂都有可能导致页面的饱和度降低,也就是实际保存真实数据的空间变少了。
检查单个页面
page-dump
命令能够转储[dump
]关于单个页面的所有信息。目前它严重依赖于 Ruby
中经典的美化打印[pretty-printer
] 模块 pp
来打印这些结构,清理这个依赖将是未来需要做的一件大事。innodb_ruby
会首先使用最基本的 Innodb::Page
类解析页面,然后根据通用 Header
中的 type
字段将不同的类型的页面交给专门的类进行进一步解析(如 Innodb::Page::INDEX
类用于解析 INDEX
类型的页面)。
我们来观察一下空间中第一个 INDEX
页面,也就是是上面创建的测试表的索引树的根节点,它位于3
号页面:
第一行输出会告诉你哪个类正在处理这个页面:
紧接着是 FIL Header
的信息:
FIL Header
和 FIL Trailer
对于所有页面类型都是通用的,主要包含有关页面自身的相关信息。
而除此之外的其他信息则取决于页面的类型;对于 INDEX
类型页面,page-dump
命令会转储以下信息:
“页面头部[
page header
]”,关于INDEX
类型 页面的相关信息“文件段头部[
fseg header
]”,有关该索引使用的文件段(文件段可以视为一组区段)的空间管理信息页面不同部分的空间大小统计(以字节为单位): 空闲空间、数据占用空间以及记录大小 等
系统记录[
system records
],infimum
记录和supremum
记录页面目录[
page directory
]的内容,用于提高记录搜索的效率用户记录[
records
],由用户存储的实际数据(只有加载了“记录描述器[record describer
]”,用户记录中具体的字段才会被解析)
译者注:
infimum
记录和supremum
记录是InnoDB
中的INDEX
类型的页面中用于表示“无穷小”和“无穷大”的两条特殊记录。
看看索引空间的消耗
使用 space-index-pages-summary
命令可以看到 INDEX
页面的一些重要的空间消耗数据:
通过输出你可以看到数据占用空间、空闲空间以及表中的记录数量。
如果你已经安装了 gnuplot
,并且安装了 Ruby gnuplot gem
,那么就很容易为这些信息制作一个有用的散点图(尽管不是很漂亮) :
space-index-pages-free-plot
命令生成的图如下:
y轴
表示每页的空闲空间大小,x轴
表示页码,同时也表示文件偏移量。
理解行数据
为了使innodb_ruby
在检查实际表时发挥作用,需要为其提供一些理解表结构的方法。这可以通过"describer"
类来完成,该类是可以动态加载的。这是 innodb_ruby
没有良好文档记录(或良好设计)的一个方面。上述表(表结构为i INT UNSIGNED NOT NULL, PRIMARY KEY (i)
并且没有其他的索引)的一个简单的描述类[describer classs
]如下:
将这个类保存在一个simple_t_describer.rb
文件中,便可以在 innodb_space
中使用 -r <file>
加载 ,并使用-d <class>
参数启用:
加载 记录描述器[record describer
] 主要完成了两件事:
在
page-dump
命令中启用记录解析和转储。这可以使得:key
和:row
能够被填充到转储的记录中,还包括事务ID
[transaction ID
] 和回滚指针
[roll pointer
](这两个隐藏字段在存储位置上位于键字段
和非主键字段
之间,因此至少需要知道如何解析键字段
才能访问这两个隐藏字段)允许使用所有的索引递归功能,包括
index-recurse
命令。为了解析InnoDB
的B+树
中的“节点指针记录[node point record
]”,需要解析记录内容的能力,
译者注:
事务ID
和回滚指针
是在主键索引中每条记录都有的隐藏字段
:key
和:row
在记录描述器[record describer
]中分别用来描述一个索引中的键字段
和非键字段
。在主键索引中键字段
包含主键定义中的所有字段,非键字段
包含表定义的其他字段;在二级索引中,键字段
包含二级索引定义的所有字段,非键字段
包含所有的主键字段。“节点指针记录[
node point record
]” 指的是InnoDB
B+
树中的非叶子结点页面中的记录,其中的记录在索引信息之后还包含子节点的页码,所以需要先解析索引字段才能够得到子结点的页码,以便进行索引遍历。
这里有一些示例页面的完整转储记录:test_t_page_3_page_dump.txt (索引根页面)和 test_t_page_4_page_dump.txt (索引叶子页面)。
递归索引
有了记录描述器之后,就可以使用 index-recurse
命令 递归遍历索引:
这实际上会按照升序遍历 B+树
(也就是全表扫描) ,同时打印出遍历到的每个节点(也就是页面)的一些信息,并转储叶子结点页面上的用户记录。这里有一个更大的输出示例(10k
行):test_t_page_3_index_recurse.txt。
未来还会有更多
我希望这是一个有用的入门介绍。未来还会有更多有关innodb_ruby
的介绍。非常欢迎提供补丁,评论和建议!
更新 1: Davi 指出了一些已经更正的错误和错误。:) 确保你使用的是上面例子中的最新代码。
版权声明: 本文为 InfoQ 作者【keaper】的原创文章。
原文链接:【http://xie.infoq.cn/article/a6ef07d833f1336be3ff31284】。文章转载请联系作者。
评论