innodb行宽几百字节 ,千万行记录,索引深度多少?

170 阅读4分钟
原文链接: click.aliyun.com

root@localhost:mysql3307.sock [db1] 11:30:05> show create table page\G *************************** 1. row *************************** Table: page Create Table: CREATE TABLE `page` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(100) DEFAULT NULL, `text` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=11831127 DEFAULT CHARSET=utf8 1 row in set (0.00 sec)

root@localhost:mysql3307.sock [db1] 11:28:46> select count(*) from page; +----------+ | count(*) | +----------+ | 11831126 | +----------+ 1 row in set (1.95 sec)

查看平均行大小 root@localhost:mysql3307.sock [db1] 11:27:35> show table status like 'page'\G *************************** 1. row *************************** Name: page Engine: InnoDB Version: 10 Row_format: Dynamic Rows: 11822697 Avg_row_length: 394 Data_length: 4661968896 Max_data_length: 0 Index_length: 0 Data_free: 5242880 Auto_increment: 11831127 Create_time: 2018-08-25 11:23:11 Update_time: 2018-08-25 11:27:12 Check_time: NULL Collation: utf8_general_ci Checksum: NULL Create_options: Comment: 1 row in set (0.00 sec)


root@localhost:mysql3307.sock [db1] 11:28:38> select * from mysql.innodb_index_stats where table_name='page'; +---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+ | database_name | table_name | index_name | last_update | stat_name | stat_value | sample_size | stat_description | +---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+ | db1 | page | PRIMARY | 2018-08-25 11:28:12 | n_diff_pfx01 | 12172354 | 20 | id | | db1 | page | PRIMARY | 2018-08-25 11:28:12 | n_leaf_pages | 251755 | NULL | Number of leaf pages in the index | | db1 | page | PRIMARY | 2018-08-25 11:28:12 | size | 288128 | NULL | Number of pages in the index | +---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+ 3 rows in set (0.00 sec)
root@localhost:mysql3307.sock [db1] 11:31:23> select * from mysql.innodb_table_stats where table_name='page'; +---------------+------------+---------------------+----------+----------------------+--------------------------+ | database_name | table_name | last_update | n_rows | clustered_index_size | sum_of_other_index_sizes | +---------------+------------+---------------------+----------+----------------------+--------------------------+ | db1 | page | 2018-08-25 11:28:12 | 12172354 | 288128 | 0 | +---------------+------------+---------------------+----------+----------------------+--------------------------+
平均一页多少记录? root@localhost:mysql3307.sock [db1] 11:32:33> select 11831126/288128; +-----------------+ | 11831126/288128 | +-----------------+ | 41.0620 | +-----------------+ 1 row in set (0.00 sec)
查看索引高度


InnoDB是索引组织表,每个页都包含一个PAGE_LEVEL的信息,用于表示当前页所在索引中的高度。默认叶子节点的高度为0,那么root页的PAGE_LEVEL + 1就是这棵索引的高度。在第三个页FIL_PAGE_INODE 索引页,这个索引页是聚集索引的root,Root页的位置通常是不会更改的,接下去的问题就是怎样得到一张表所有索引的Root页所在的位置呢?
root@localhost:mysql3307.sock [db1] 11:51:29> SELECT b.name, a.name, index_id, type, a.space, a.PAGE_NO FROM information_schema.INNODB_SYS_INDEXES a, information_schema.INNODB_SYS_TABLES b WHERE a.table_id = b.table_id and b.name='db1/page'; +----------+---------+----------+------+-------+---------+ | name | name | index_id | type | space | PAGE_NO | +----------+---------+----------+------+-------+---------+ | db1/page | PRIMARY | 133 | 3 | 100 | 3 | +----------+---------+----------+------+-------+---------+ 1 row in set (0.00 sec)
root@localhost:mysql3307.sock [db1] 11:55:26> show variables like '%innodb_page%'; +----------------------+-------+ | Variable_name | Value | +----------------------+-------+ | innodb_page_cleaners | 4 | | innodb_page_size | 16384 | +----------------------+-------+ 2 rows in set (0.00 sec)

有了这些信息就可以方便的定位啦,因为PAGE_LEVEL在每个页的偏移量64位置出,占用两个字节,通过hexdump这样的工具就可以快速定位到所需要的树高度信息: [root@db001 db1]# hexdump -C -s 49216 -n 10 page.ibd 0000c040 00 02 00 00 00 00 00 00 00 85
查看page表,49216表示的是3*16384+64,即第3个页偏移量64位置开始读取10个字节,但不是读取2个字节就可以了嘛?其实因为后面8个字节对应的是index_id,这里index_id是00 85 即133, PAGE_LEVEL为0002,那么索引的高度就为3。

继续插入记录到3亿多记录时候索引高度变成4 root@localhost:mysql3307.sock [db1] 14:00:31> show create table page\G *************************** 1. row *************************** Table: page Create Table: CREATE TABLE `page` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(100) DEFAULT NULL, `text` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=341490301 DEFAULT CHARSET=utf8 1 row in set (0.00 sec)
[root@db001 db1]# hexdump -C -s 49216 -n 10 page.ibd 0000c040 00 03 00 00 00 00 00 00 00 85
虽然通常来说索引树的高度为3~4层,但是极端情况下,比如数据量超级大,页比较小,如4K,那么高度也是可能破4的。
hexdump命令一般用来查看“二进制”文件的十六进制编码,但实际上它能查看任何文件,而不只限于二进制文件。 语法 hexdump [选项] [文件]... 选项 -n length 只格式化输入文件的前length个字节。 -C 输出规范的十六进制和ASCII码。 -b 单字节八进制显示。 -c 单字节字符显示。 -d 双字节十进制显示。 -o 双字节八进制显示。 -x 双字节十六进制显示。 -s 从偏移量开始输出。 -e 指定格式字符串,格式字符串包含在一对单引号中,格式字符串形如:'a/b "format1" "format2"'。