analyze table 有时无效,因统计信息非实时更新、采样页数少(默认20)、数据倾斜时误判索引选择性;大表需调高 innodb_stats_sample_pages,分区表需 for full,pg 需提高 statistics_target,sql server 需关注 modification_counter 阈值,迁移后必须重建统计。

为什么 ANALYZE TABLE 有时没用?
因为 MySQL 的统计信息不是实时更新的,也不是每次查询都自动刷新。执行 ANALYZE TABLE 后,如果表数据变化不大(比如只增删几行),优化器可能沿用旧统计;更关键的是,它默认只采样部分页(innodb_stats_sample_pages 默认 20),小样本遇上数据倾斜就容易误判索引选择性。
- 大表务必调高
innodb_stats_sample_pages(如设为 100 或 200),但别盲目设太高——会拖慢ANALYZE本身 - 避免在业务高峰期跑
ANALYZE TABLE,InnoDB 会加元数据锁,阻塞 DDL - 对分区表,
ANALYZE TABLE默认只分析一级分区元数据,要加FOR FULL(MySQL 8.0.23+)才真正扫描数据
PostgreSQL 怎么让 ANALYZE 更准?
PG 的 ANALYZE 默认只抽样 300 行(由 default_statistics_target 控制),对字段值分布不均的列(比如状态码 99% 是 0、1% 是 1)极易低估高频值频次,导致执行计划选错索引。
- 对关键查询字段,用
ALTER TABLE ... ALTER COLUMN ... SET STATISTICS 500提高采样精度(最大 10000) - 定期执行
ANALYZE VERBOSE table_name看实际采样行数和最常见值(MCV)列表,确认是否覆盖了你的业务热点值 - 不要依赖自动 vacuum ——
autovacuum_analyze_scale_factor默认 0.1,意味着 1000 万行的表要改 100 万行才触发,远不够用
SQL Server 统计信息过期怎么快速定位?
SQL Server 不报“统计信息过期”,而是默默用陈旧数据生成低效执行计划。判断依据是修改行数占比:当表总行数 × modification_counter / rowcnt > 阈值(小表 500 行、大表 20%)时即视为过期。
- 查过期情况:运行
DBCC SHOW_STATISTICS('table_name', 'stat_name') WITH STAT_HEADER,看Rows Modified和Rows比值 - 强制更新单个统计:
UPDATE STATISTICS table_name stat_name WITH FULLSCAN,比默认采样更稳,但锁表时间长 - 禁用自动更新(
NORECOMPUTE)必须慎用——一旦关了,后续所有 INSERT/UPDATE/DELETE 都不会触发更新,只能手动维护
跨数据库迁移后统计信息必须重做
导出再导入数据(哪怕用 mysqldump 或 pg_dump)不会保留原库的统计信息。新库初始化后,所有表的统计都是空或极简的,优化器大概率走全表扫描,而不是你预期的索引路径。
- MySQL 导入后立刻跑
ANALYZE TABLE,别等慢查询报警才想起这事 - PostgreSQL 导入后执行
VACUUM ANALYZE,比单独ANALYZE多一步清理死元组,更贴近生产状态 - SQL Server 迁移后用
EXEC sp_MSforeachtable 'UPDATE STATISTICS ? WITH FULLSCAN'批量重建,别漏掉系统表以外的任何用户表
统计信息不是“设一次就完事”的配置,它是随数据一起呼吸的活体——改得勤、看得清、信得准,才能让优化器真听你的话。最常被忽略的,其实是采样精度和触发阈值这两个参数,它们比命令本身更能决定结果好坏。









