bigywater.tech
MySQL / InnoDB · 32

持久化统计信息

查mysql.innodb_table_stats和innodb_index_stats系统表,看统计信息的具体样子,再验证关掉持久化后统计信息完全不进这两张表。

n_rows=499494
的表级持久化统计数字
n_diff_pfx01=1
体现的抽样误差(应为2)
空结果
STATS_PERSISTENT=0的表不进系统表

做的事:直接查统计信息存在哪里

innodb_stats_persistent=ON(默认)意味着统计信息被写进了两张系统表。

结果SELECT * FROM mysql.innodb_table_stats WHERE table_name='t13'; → n_rows: 499494 → clustered_index_size: 1057 → sum_of_other_index_sizes: 545

验证:索引级别的统计,精确到每个索引的每一列

另一张表存的是更细粒度的信息。

结果SELECT * FROM mysql.innodb_index_stats WHERE table_name='t13' LIMIT 5; → PRIMARY n_diff_pfx01 499494 sample_size=20 (id) → PRIMARY n_leaf_pages 1003 (NULL) → PRIMARY size 1057 (NULL) → idx_status n_diff_pfx01 1 sample_size=3 (status) → idx_status n_diff_pfx02 500580 sample_size=20 (status,id)

看到 idx_status 索引上 n_diff_pfx01(第1列即status的不同值数量估算)是1——这个数字本身就暴露了问题:status只有active/banned两个不同值,估算成1明显是错的(应该是2),这也印证了上一篇讲的"抽样带来的误差",抽中的样本页面里,可能只采到了一种值。sample_size 字段则直接告诉你这次统计用了多少个页面做的抽样。

验证:STATS_PERSISTENT=0的表,压根不会出现在这两张表里

如果关掉持久化,统计信息存在哪里。

结果CREATE TABLE t14 (...) STATS_PERSISTENT=0; 插入10万行,执行ANALYZE TABLE t14; SELECT * FROM mysql.innodb_table_stats WHERE table_name='t14'; → :空结果(一行都没有!)
哪怕对t14执行过 ANALYZE TABLE,mysql.innodb_table_stats 里也查不到它的任何记录——STATS_PERSISTENT=0 意味着这张表的统计信息只会存在于内存里,服务器一重启就彻底丢失,得重新用少量查询触发的临时估算或者显式ANALYZE来重建。这也是为什么 innodb_stats_persistent(的全局默认值)从MySQL 5.6起就默认是ON:持久化统计信息能保证服务器重启后,优化器不会因为"统计信息突然清零、需要重新摸索"而在刚重启的一段时间里做出更差的执行计划选择——这在的生产环境里是个不小的稳定性提升。

分步演示:统计信息存在哪里

每一步都是本文上面查询mysql系统库得到的原始结果。

持久化统计信息存在两张系统表里,关掉就只在内存
这一步新验证的结果

    本文用到的工具

    • 本机 MySQL 26.7.0(InnoDB)
    • mysql.innodb_table_stats / mysql.innodb_index_stats / STATS_PERSISTENT=0:验证统计信息的持久化位置
    京ICP备2026067502号-1京公网安备11010502063487号