MySQL统计信息不准怎么办?如何查看MySQL统计信息
- 虚拟主机
- 2026-06-18
- 7
MySQL 的优化器(Optimizer)是数据库执行查询计划的核心组件,而统计信息则是优化器做出决策的“眼睛”,如果没有准确、及时的统计信息,优化器将无法评估不同执行计划(如全表扫描 vs 索引扫描)的成本,从而导致性能低下甚至查询超时,以下是对 MySQL 统计信息的详细解析。
统计信息的来源与存储机制
在 MySQL 5.6 及更早版本中,统计信息主要存储在内存中,每次重启都会丢失,且更新频率较低,通常依赖于 ANALYZE TABLE 命令手动触发,从 MySQL 5.7 开始,引入了持久化统计信息,将统计信息存储在系统表 mysql.innodb_table_stats 和 mysql.innodb_index_stats 中,即使服务器重启也不会丢失。
到了 MySQL 8.0,统计信息的收集机制发生了重大变革,除了传统的基于采样的统计信息外,MySQL 8.0 引入了直方图(Histograms)功能,能够更精确地描述数据分布,特别是对于数据倾斜严重的列,MySQL 8.0.30+ 版本还引入了增量统计信息更新,减少了全表扫描带来的性能开销。
统计信息主要包含以下核心指标:
- 基数(Cardinality):表中唯一值的数量,对于索引列,基数越接近表行数,索引选择性越高。
- 页数量(Page Count):索引或表占用的数据页数量,用于估算 I/O 成本。
- 数据分布:通过直方图记录列值的频率分布,帮助优化器判断范围查询的选择性。
统计信息的收集与更新策略
统计信息的准确性直接决定查询性能,但频繁更新统计信息会带来巨大的系统开销,理解何时以及如何更新统计信息至关重要。
自动更新机制
MySQL 8.0 引入了自动统计信息更新功能,当表中的数据发生显著变化(默认阈值为 10%)时,后台线程会自动触发统计信息更新,这一机制通过 innodb_stats_auto_recalc

参数控制,默认开启。
手动更新
DBA 可以在数据大量变更后手动执行 ANALYZE TABLE 命令,该命令会重新扫描表或索引以生成最新的统计信息,需要注意的是,ANALYZE TABLE 会锁表(或锁索引),在生产环境中需谨慎使用,建议在低峰期执行。
采样与全表扫描
对于大表,全表扫描成本极高,MySQL 默认采用采样策略,即只扫描部分数据页来估算统计信息,采样率可以通过 innodb_stats_persistent_sample_pages 参数调整,默认值为 20,采样率越高,统计信息越准确,但收集成本也越高。
统计信息的关键参数配置
合理配置统计信息相关的参数,可以在性能与准确性之间找到平衡点,以下是几个关键参数的说明:
| 参数名称 | 默认值 | 说明 |
|---|---|---|
| innodb_stats_auto_recalc | ON | 是否启用自动统计信息更新,当表数据变化超过阈值时自动触发。 |
| innodb_stats_persistent | ON | 是否持久化统计信息到磁盘,关闭后统计信息仅存在于内存中。 |
| innodb_stats_persistent_sample_pages | 20 | 持久化统计信息采样时的页数量,增加此值可提高准确性,但增加收集时间。 |
| innodb_stats_transient_sample_pages | 8 | 非持久化(内存中)统计信息采样时的页数量。 |
| innodb_stats_on_metadata
| OFF | 是否在查询元数据时更新统计信息,建议保持关闭,以避免元数据查询阻塞。 |
| innodb_stats_include_delete_marked | OFF | 是否在统计中包含被标记为删除的行,通常建议关闭,除非数据删除率极高。 |

