innodb_ruby 是使用 Ruby 编写的 InnoDB 文件格式解析器。innodb_ruby 的目的是暴露一些其余隐藏的 InnoDB 原理。node
innodb_ruby不适合使用于生产环境,但能够做为学习工具来使用。mysql
如下安装参考MySQL大师知数堂吴炳锡老师的blog.git
下载github
[root@MySQL56_L1 mysql]# wget https://cache.ruby-china.org/pub/ruby/ruby-1.9.3-p551.tar.gz --2017-01-19 14:06:35-- https://cache.ruby-china.org/pub/ruby/ruby-1.9.3-p551.tar.gz Resolving cache.ruby-china.org... 183.61.64.66, 121.201.98.27, 2405:fd80:110:0:d63d:7eff:fe73:c46, ... Connecting to cache.ruby-china.org|183.61.64.66|:443... connected. ERROR: certificate common name “*.b0.upaiyun.com” doesn’t match requested host name “cache.ruby-china.org”. To connect to cache.ruby-china.org insecurely, use ‘--no-check-certificate’. [root@MySQL56_L1 mysql]# wget --no-check-certificate https://cache.ruby-china.org/pub/ruby/ruby-1.9.3-p551.tar.gz --2017-01-19 14:07:31-- https://cache.ruby-china.org/pub/ruby/ruby-1.9.3-p551.tar.gz Resolving cache.ruby-china.org... 121.201.98.27, 183.61.64.66, 2405:fd80:110:0:d63d:7eff:fe73:165a, ... Connecting to cache.ruby-china.org|121.201.98.27|:443... connected. WARNING: certificate common name “*.b0.upaiyun.com” doesn’t match requested host name “cache.ruby-china.org”. HTTP request sent, awaiting response... 200 OK Length: 12605119 (12M) [application/octet-stream] Saving to: “ruby-1.9.3-p551.tar.gz” 100%[=================================================================================================================>] 12,605,119 287K/s in 47s 2017-01-19 14:08:23 (262 KB/s) - “ruby-1.9.3-p551.tar.gz” saved [12605119/12605119]
安装依赖sql
[root@MySQL56_L1 mysql]# yum -y install zlib-devel curl-devel openssl-devel httpd-devel apr-devel apr-util-devel
解压centos
[root@MySQL56_L1 mysql]# tar -zxvf ruby-1.9.3-p551.tar.gz
配置&安装ruby
[root@MySQL56_L1 ruby-1.9.3-p551]# ./configure [root@MySQL56_L1 ruby-1.9.3-p551]# make && make install [root@MySQL56_L1 ruby-1.9.3-p551]# gem install innodb_ruby
工欲善其事,必先利其器,使用以前要先查看帮助,知数堂吴炳锡老师的blog上也有介绍做者的github地址。但更详细的使用方法仍是使用--help进行查看app
[root@MySQL56_L1 data]# innodb_space --help
Usage: innodb_space <options> <mode> Invocation examples: innodb_space -s ibdata1 [-T tname [-I iname]] [options] <mode> Use ibdata1 as the system tablespace and load the tname table (and the iname index for modes that require it) from data located in the system tablespace data dictionary. This will automatically generate a record describer for any indexes. innodb_space -f tname.ibd [-r ./desc.rb -d DescClass] [options] <mode> Use the tname.ibd table (and the DescClass describer where required). The following options are supported: --help, -? Print this usage text. --trace, -t Enable tracing of all data read. Specify twice to enable even more tracing (including reads during opening of the tablespace) which can be quite noisy. --system-space-file, -s <arg> Load the system tablespace file or files <arg>: Either a single file e.g. "ibdata1", a comma-delimited list of files e.g. "ibdata1,ibdata1", or a directory name. If a directory name is provided, it will be scanned for all files named "ibdata?" which will then be sorted alphabetically and used to load the system tablespace. --table-name, -T <name> Use the table name <name>. --index-name, -I <name> Use the index name <name>. --space-file, -f <file> Load the tablespace file <file>. --page, -p <page> Operate on the page <page>. --level, -l <level> Operate on the level <level>. --list, -L <list> Operate on the list <list>. --require, -r <file> Use Ruby's "require" to load the file <file>. This is useful for loading classes with record describers. --describer, -d <describer> Use the named record describer to parse records in index pages. The following modes are supported: system-spaces Print a summary of all spaces in the system. data-dictionary-tables Print all records in the SYS_TABLES data dictionary table. data-dictionary-columns Print all records in the SYS_COLUMNS data dictionary table. data-dictionary-indexes Print all records in the SYS_INDEXES data dictionary table. data-dictionary-fields Print all records in the SYS_FIELDS data dictionary table. space-summary Summarize all pages within a tablespace. A starting page number can be provided with the --page/-p argument. space-index-pages-summary Summarize all "INDEX" pages within a tablespace. This is useful to analyze page fill rates and record counts per page. In addition to "INDEX" pages, "ALLOCATED" pages are also printed and assumed to be completely empty. A starting page number can be provided with the --page/-p argument. space-index-pages-free-plot Use Ruby's gnuplot module to produce a scatterplot of page free space for all "INDEX" and "ALLOCATED" pages in a tablespace. More aesthetically pleasing plots can be produced with space-index-pages-summary output, but this is a quick and easy way to produce a passable plot. A starting page number can be provided with the --page/-p argument. space-page-type-regions Summarize all contiguous regions of the same page type. This is useful to provide an overall view of the space and allocations within it. A starting page number can be provided with the --page/-p argument. space-page-type-summary Summarize all pages by type. A starting page number can be provided with the --page/-p argument. space-indexes Summarize all indexes (actually each segment of the indexes) to show the number of pages used and allocated, and the segment fill factor. space-lists Print a summary of all lists in a space. space-list-iterate Iterate through the contents of a space list. space-extents Iterate through all extents, printing the extent descriptor bitmap. space-extents-illustrate Iterate through all extents, illustrating the extent usage using ANSI color and Unicode box drawing characters to show page usage throughout the space. space-extents-illustrate-svg Iterate through all extents, illustrating the extent usage in SVG format printed to stdout to show page usage throughout the space. space-lsn-age-illustrate Iterate through all pages, producing a heat map colored by the page LSN using ANSI color and Unicode box drawing characters, allowing the user to get an overview of page modification recency. space-lsn-age-illustrate-svg Iterate through all pages, producing a heat map colored by the page LSN producing SVG format output, allowing the user to get an overview of page modification recency. space-inodes-summary Iterate through all inodes, printing a short summary of each FSEG. space-inodes-detail Iterate through all inodes, printing a detailed report of each FSEG. index-recurse Recurse an index, starting at the root (which must be provided in the first --page/-p argument), printing the node pages, node pointers (links), leaf pages. A record describer must be provided with the --describer/-d argument to recurse indexes (in order to parse node pages). index-record-offsets Recurse an index as index-recurse does, but print the offsets of each record within the page. index-digraph Recurse an index as index-recurse does, but print a dot-compatible digraph instead of a human-readable summary. index-level-summary Print a summary of all pages at a given level (provided with the --level/-l argument) in an index. index-fseg-internal-lists index-fseg-leaf-lists Print a summary of all lists in an index file segment. Index root page must be provided with --page/-p. index-fseg-internal-list-iterate index-fseg-leaf-list-iterate Iterate the file segment list (whose name is provided in the first --list/-L argument) for internal or leaf pages for a given index (whose root page is provided in the first --page/-p argument). The lists used for each index are "full", "not_full", and "free". index-fseg-internal-frag-pages index-fseg-leaf-frag-pages Print a summary of all fragment pages in an index file segment. Index root page must be provided with --page/-p. page-dump Dump the contents of a page, using the Ruby pp ("pretty-print") module. page-account Account for a page's usage in FSEGs. page-validate Validate the contents of a page. page-directory-summary Summarize the record contents of the page directory in a page. If a record describer is available, the key of each record will be printed. page-records Summarize all records within a page. page-illustrate Produce an illustration of the contents of a page. record-dump Dump a detailed description of a record and the data it contains. A record offset must be provided with -R/--record. record-history Summarize the history (undo logs) for a record. A record offset must be provided with -R/--record. undo-history-summary Summarize all records in the history list (undo logs). undo-record-dump Dump a detailed description of an undo record and the data it contains. A record offset must be provided with -R/--record. [root@MySQL56_L1 data]#
建立测试表curl
CREATE TABLE `t2` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) DEFAULT NULL, `remark` varchar(50) DEFAULT NULL, `add_time` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `ix_t2_name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=3829 DEFAULT CHARSET=utf8
插入测试数据(请移步到百度网盘)ide
使用innodb_space来查看t2表的索引结构、数据分配状况
space-indexes:Summarize all indexes (actually each segment of the indexes) to show the number of pages used and allocated, and the segment fill factor()
[root@MySQL56_L1 data]# innodb_space -s ibdata1 -T zeno3376/t2 space-indexes id name root fseg used allocated fill_factor 42 PRIMARY 3 internal 1 1 100.00% 42 PRIMARY 3 leaf 9 9 100.00% 43 ix_t2_name 4 internal 1 1 100.00% 43 ix_t2_name 4 leaf 4 4 100.00%
name:索引的名称;PRIMARY表明的就是汇集索引,由于InnoDB表是汇集因此组织表,行记录就是汇集索引;ix_t2_name就是辅助索引的名称
root:索引中根节点的page number;能够看出汇集索引的根节点是第3个page(为何是从第三个page开始,看下文space-page-type-regions),辅助索引的根节点是第4个page
fseg:page的说明
used:索引使用了多少个page;能够看出汇集索引的根几点使用了1个page,叶子节点使用了9个page;辅助索引ix_t2_name的叶子节点使用了4个page
allocated: 索引分配了多少个page;能够看出汇集索引的根几点分配了1个page,叶子节点分配了9个page;辅助索引ix_t2_name的叶子节点分配了4个page
fill_factor:索引的填充度;全部的填充度都是100%
space-page-type-regions:Summarize all contiguous regions of the same page type. This is useful to provide an overall view of the space and allocations within it. A starting page number can be provided with the --page/-p argument.(统计每一个类型的页共占用了多少页)
[root@MySQL56_L1 data]# innodb_space -s ibdata1 -T zeno3376/t2 space-page-type-regions start end count type 0 0 1 FSP_HDR 1 1 1 IBUF_BITMAP 2 2 1 INODE 3 17 15 INDEX 18 18 1 FREE (ALLOCATED)
start:从第几个page开始
end:从第几个page结束
count:占用了多少个page;
type: page的类型
从上面的结果能够看出:“FSP_HDR”、“IBUF_BITMAP”、“INODE”是分别占用了0,1,2号的page,从3号page开始才是存放数据和索引的页(Index),占用了3~17号的page,共15个page。
接下来,根据获得的汇集索引和辅助索引的根节点来获取索引上的其余page的信息
page-records:Summarize all records within a page.
# 解析表(汇集索引组织表,这里不须要加-I primary,不然会报错) [root@MySQL56_L1 data]# innodb_space -s ibdata1 -T zeno3376/t2 -I primary -p 3 page-records /usr/local/lib/ruby/gems/1.9.1/gems/innodb_ruby-0.9.15/lib/innodb/system.rb:213:in `index_by_name': undefined method `[]' for nil:NilClass (NoMethodError) from /usr/local/lib/ruby/gems/1.9.1/gems/innodb_ruby-0.9.15/bin/innodb_space:1913:in `<top (required)>' from /usr/local/bin/innodb_space:23:in `load' from /usr/local/bin/innodb_space:23:in `<main>' [root@MySQL56_L1 data]# innodb_space -s ibdata1 -T zeno3376/t2 -p 3 page-records Record 126: (id=1782) → #5 Record 140: (id=1890) → #6 Record 154: (id=2101) → #7 Record 168: (id=2317) → #10 Record 182: (id=2531) → #11 Record 196: (id=2747) → #12 Record 210: (id=2964) → #15 Record 224: (id=3179) → #16 Record 238: (id=3394) → #17
# -p 3 就是解析3号page的意思
上面的结果是解析汇集索引根节点页的信息,1行就表明使用了1个page,因此,叶子节点共使用了9个page,根节点使用了1个page,跟space_indexes的解析结果一致。
Record 126: (id=1782) → #5
id = 1782 表明的就是表中id为1782的记录,由于id是主键
-> #5 表明的是指向5号page
Record 126: (id=1782) → #5: 整行的意思就是5号page的id最小值是1782,包含了1782~1889的行记录。
注意:page number并非连续的
根据解析root获得的信息,继续解析第一个叶子节点的信息
[root@MySQL56_L1 data]# innodb_space -s ibdata1 -T zeno3376/t2 -p 5 page-records Record 128: (id=1782) → (name="zeno", remark="mysql", add_time=:NULL) Record 162: (id=1783) → (name="KIK91QJET1FCZ46EJKML", remark="H4HJO5F7W5GSSDORT8AAT", add_time="184524556-49-63 92:14:08") Record 233: (id=1784) → (name="XQZJ08164WSB2EI9M3HCWCEZZOXNB6", remark="8878ASA5AW", add_time="184524556-50-65 04:03:84") Record 303: (id=1785) → (name="XAXK7RVVTYWEXB2ZFB", remark="TVZNZPW150ZNNJAC1", add_time="184524556-50-65 16:99:20") Record 368: (id=1786) → (name="G0BZFYV26V14", remark="CYYVCNQJVDQ4OLO6YBZ", add_time="184524556-50-65 63:27:68") …… # 注:已截断部分数据 Record 7187: (id=1885) → (name="XQ2E35QOX32I5GL0TH", remark="SZ4QTI116S3ISRZOJL0M", add_time="184524556-52-49 52:32:00") Record 7255: (id=1886) → (name="S127FSHO2IPIE2", remark="2EX67306JBI7AL9Z", add_time="184524556-52-49 72:18:56") Record 7315: (id=1887) → (name="2XKN9VXB5561923IPKVMBW", remark="6ZBU7PRXNDUHR4DV2PB", add_time="184524556-52-49 19:62:88") Record 7386: (id=1888) → (name="42R60NM6IMTNHRB1L", remark="UG3GLX6ONU5", add_time="184524556-52-49 45:81:76") Record 7444: (id=1889) → (name="0O2S6OCUC99MQKM1", remark="1K5GJEQ5QU83T3F", add_time="184524556-52-49 32:71:04")
从上面能够看出,汇集索引的叶子节点是包含了行记录的全部数据。
同理,解析辅助索引ix_t2_name,可是须要注意的是,在解析辅助索引是,须要加上“-I ix_t2_name”
[root@MySQL56_L1 data]# innodb_space -s ibdata1 -T zeno3376/t2 -I ix_t2_name -p 4 page-records Record 127: (name="01EE2CCYUW35K0LVT5DAG2044NW") → #8 Record 196: (name="8WCS36CV56KGA8NE6OG23QFS") → #13 Record 169: (name="HQVX6ZX7H2XI") → #9 Record 235: (name="QXS8RUJF6FY") → #14
从上面能够出,辅助索引ix_t2_name的key是name列,叶子节点共使用了4个page,加上根节点,那么辅助索引ix_t2_name共使用了5个page,跟使用space_indexes解析出来的结果一致。
Record 127: (name="01EE2CCYUW35K0LVT5DAG2044NW") → #8 这条记录表明的意思是辅助索引的第1个叶子节点的page number是8,8号page的第一个key值是"01EE2CCYUW35K0LVT5DAG2044NW"
Record 196: (name="8WCS36CV56KGA8NE6OG23QFS") → #13 这条记录表明的意思是辅助索引的第2个叶子节点的page number是13,13号page的第一个key值是"8WCS36CV56KGA8NE6OG23QFS"
其它的记录如此类推……
接下来看看辅助索引的叶子节点的结构
[root@MySQL56_L1 data]# innodb_space -s ibdata1 -T zeno3376/t2 -I ix_t2_name -p 8 page-records Record 127: (name="01EE2CCYUW35K0LVT5DAG2044NW") → (id=1855) Record 165: (name="02RFY8SJLQ879F2CYHI") → (id=2132) Record 10829: (name="04FNKNM16R7U27A3") → (id=3152) Record 195: (name="06WM2Q51B0D8L76VM2") → (id=2184) Record 224: (name="0739V9NMP4") → (id=1843) ……# 注:已截断部分信息 Record 8197: (name="8U4049BA2TAAY7A89SDG") → (id=2003) Record 10591: (name="8UQOOOU7X5AYE75GU") → (id=3111) Record 8228: (name="8V5C6OGK4NGAHE6") → (id=2247) Record 12607: (name="8V6SFJ0P8E1XKIF005QD3NTCI") → (id=3435) Record 9595: (name="8VK9HHEN3G") → (id=2972)
从上面能够看到叶子节点中包含可辅助索引和主键列
Record 127: (name="01EE2CCYUW35K0LVT5DAG2044NW") → (id=1855) 表明的意思就是name值为"01EE2CCYUW35K0LVT5DAG2044NW"的记录指向主键id=1855的行记录。
其余的记录同理。
以上,若有错谬,请不吝指出。