玩命加载中 . . .

13-InnoDB统计数据是如何收集的


13.1 统计数据的存储方式

  • 永久性的统计数据:这种统计数据存储在磁盘上,也就是服务器重启之后这些统计数据还在
  • 非永久性的统计数据:这种统计数据存储在内存中,当服务器关闭时这些这些统计数据就都被清除掉了,等到服务器重启之后,在某些适当的场景下才会重新收集这些统计数据

13.2 基于磁盘的永久性统计数据

当我们选择把某个表以及该表索引的统计数据存放到磁盘上时,实际上是把这些统计数据存储到了两个表里

mysql> show tables from mysql like 'innodb%stats';
+--------------------------------+
| Tables_in_mysql (innodb%stats) |
+--------------------------------+
| innodb_index_stats             |
| innodb_table_stats             |
+--------------------------------+
  • innodb_table_stats存储了关于表的统计数据,每一条记录对应着一个表的统计数据
  • innodb_index_stats存储了关于索引的统计数据,每一条记录对应着一个索引的一个统计项的统计数据

13.2.1 innodb_table_stats

字段名 描述
database_name 数据库名
table_name 表名
last_update 本条记录最后更新时间
n_rows 表中记录的条数
clustered_index_size 表的聚簇索引占用的页面数量
sum_of_other_index_sizes 表的其他索引占用的页面数量

1、n_rows统计项的收集

按照一定算法从聚簇索引中选取几个叶子节点页面,计算每个页面中包含的记录数量,然后计算一个页面中平均包含的记录数量,并将其乘以全部叶子节点的数量,就是该表的n_rows

n_rows值精确与否取决于统计时采样的页面数量

系统变量innodb_stats_persistent_sample_pages用来控制使用永久性的统计数据时,计算统计数据时采样的页面数量,默认值是 20

13.2.2 innodb_index_stats

字段名 描述
database_name 数据库名
table_name 表名
index_name 索引名
last_update 本条记录最后更新时间
stat_name 统计项的名称
stat_value 对应的统计项的值
sample_size 为生成统计数据而采样的页面数量
stat_description 对应的统计项的描述

innodb_index_stats表的每条记录代表着一个索引的一个统计项

mysql> select * from mysql.innodb_index_stats where table_name = 'single_table';
+--------------+--------------+------------+-------------+-----------------------------------+
| index_name   | stat_name    | stat_value | sample_size | stat_description                  |
+--------------+--------------+------------+-------------+-----------------------------------+
| PRIMARY      | n_diff_pfx01 |          0 |           1 | id                                |
| PRIMARY      | n_leaf_pages |          1 |        NULL | Number of leaf pages in the index |
| PRIMARY      | size         |          1 |        NULL | Number of pages in the index      |
| idx_key1     | n_diff_pfx01 |          0 |           1 | key1                              |
| idx_key1     | n_diff_pfx02 |          0 |           1 | key1,id                           |
| idx_key1     | n_leaf_pages |          1 |        NULL | Number of leaf pages in the index |
| idx_key1     | size         |          1 |        NULL | Number of pages in the index      |
| idx_key3     | n_diff_pfx01 |          0 |           1 | key3                              |
| idx_key3     | n_diff_pfx02 |          0 |           1 | key3,id                           |
| idx_key3     | n_leaf_pages |          1 |        NULL | Number of leaf pages in the index |
| idx_key3     | size         |          1 |        NULL | Number of pages in the index      |
| idx_key_part | n_diff_pfx01 |          0 |           1 | key_part1                         |
| idx_key_part | n_diff_pfx02 |          0 |           1 | key_part1,key_part2               |
| idx_key_part | n_diff_pfx03 |          0 |           1 | key_part1,key_part2,key_part3     |
| idx_key_part | n_diff_pfx04 |          0 |           1 | key_part1,key_part2,key_part3,id  |
| idx_key_part | n_leaf_pages |          1 |        NULL | Number of leaf pages in the index |
| idx_key_part | size         |          1 |        NULL | Number of pages in the index      |
| uk_key2      | n_diff_pfx01 |          0 |           1 | key2                              |
| uk_key2      | n_leaf_pages |          1 |        NULL | Number of leaf pages in the index |
| uk_key2      | size         |          1 |        NULL | Number of pages in the index      |
+--------------+--------------+------------+-------------+-----------------------------------+

index_name列,这个列说明该记录是哪个索引的统计信息

PRIMARY索引(也就是主键)占了3条记录,idx_key_part索引占了6条记录

  • n_leaf_pages:表示该索引的叶子节点占用多少页面
  • size:表示该索引共占用多少页面
  • n_diff_pfxNN:表示对应的索引列不重复的值有多少
    • n_diff_pfx01表示的是统计key_part1这单单一个列不重复的值有多少
    • n_diff_pfx02表示的是统计key_part1、key_part2这两个列组合起来不重复的值有多少
    • n_diff_pfx03表示的是统计key_part1、key_part2、key_part3这三个列组合起来不重复的值有多少
    • n_diff_pfx04表示的是统计key_part1、key_part2、key_part3、id这四个列组合起来不重复的值有多少

13.3.3 定期更新统计数据

系统变量innodb_stats_auto_recalc决定着服务器是否自动重新计算统计数据,它的默认值是ON,也就是该功能默认是开启的。

每个表都维护了一个变量,该变量记录着对该表进行增删改的记录条数,如果发生变动的记录数量超过了表大小的 10% ,并且自动重新计算统计数据的功能是打开的,那么服务器会重新进行一次统计数据的计算,并且更新innodb_table_statsinnodb_index_stats

不过自动重新计算统计数据的过程是异步发生的,也就是即使表中变动的记录数超过了 10% ,自动重新计算统计数据也不会立即发生,可能会延迟几秒才会进行计算

  • 手动调用ANALYZE TABLE语句来更新统计信息

如果innodb_stats_auto_recalc系统变量的值为OFF的话,我们也可以手动调用ANALYZE TABLE语句来重新计算统计数据

ANALYZE TABLE语句会立即重新计算统计数据,也就是这个过程是同步的

13.4 innodb_stats_method的使用

索引列不重复的值的数量这个统计数据对于 MySQL 查询优化器十分重要,因为通过它可以计算出在索引列中平均一个值重复多少行,它的应用场景主要有两个

  • 单表查询中单点区间太多
SELECT * FROM tbl_name WHERE key IN ('xx1', 'xx2', ..., 'xxn');

IN里的参数数量过多时,采用index dive的方式直接访问 B+ 树索引去统计每个单点区间对应的记录的数量就太耗费性能了,所以直接依赖统计数据中的平均一个值重复多少行来计算单点区间对应的记录数量

  • 连接查询时,如果有涉及两个表的等值匹配连接条件,该连接条件对应的被驱动表中的列又拥有索引时,则 可以使用 ref 访问方法来对被驱动表进行查询
SELECT * FROM t1 JOIN t2 ON t1.column = t2.key WHERE ...;

在真正执行对t2表的查询前,t1.comumn的值是不确定的,所以我们也不能通过index dive的方式直接访问 B+ 树索引去统计每个单点区间对应的记录的数量,也只能依赖统计数据中的平均一个值重复多少行来计算单点区间对应的记录数量


文章作者: kunpeng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kunpeng !
  目录