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"'。