多数数据库执行DML后不自动更新统计信息,需手动ANALYZE;当修改超5%行数、增删大量重复值、VACUUM FULL后或查询计划劣化时必须执行,并注意采样精度与执行时机。

大表修改后为什么统计信息不自动更新
多数数据库(如 PostgreSQL、MySQL 8.0+ 的 InnoDB)在执行 UPDATE、DELETE 或 INSERT 后,并不会自动触发统计信息刷新。优化器依赖的行数估算、列值分布、直方图等,仍沿用旧的 ANALYZE 结果。尤其当修改量超过表总行数的 10%–20%,执行计划就容易劣化——比如该走索引却选了全表扫描。
什么时候必须手动执行 ANALYZE
以下情况建议立即运行 ANALYZE:
- 单次修改了 >5% 的数据行(例如对千万级表
UPDATE百万行) - 新增或删除了大量重复值(如批量填充某字段为相同状态码)
- 执行完
VACUUM FULL或CLUSTER(PostgreSQL)后 - 查询响应时间突增,且
EXPLAIN显示预估行数偏差 >10 倍
ANALYZE 的实际执行要点
直接运行 ANALYZE 是安全的:它只读取数据、不锁表(PostgreSQL)、不阻塞 DML;但耗时与采样量正相关。关键控制点:
- 默认只采样约 300 行(PostgreSQL),对大表完全不够——需显式指定列或调整
default_statistics_target - 可针对单列分析:
ANALYZE table_name (column_a, column_b),比全表快且更精准 - MySQL 中对应命令是
ANALYZE TABLE table_name,但仅更新索引基数,不生成直方图(需CREATE STATISTICS配合) - 避免在业务高峰执行全表
ANALYZE;若表超 1 亿行,优先用ANALYZE table_name (col) WITH (sample_rate = 0.05)(PostgreSQL 15+)
常见误操作和副作用
不是所有“重统计”都叫 ANALYZE,混淆会导致白忙活:
- 把
VACUUM当成统计更新——它只清理死元组,不更新统计信息(PostgreSQL) - 在 MySQL 5.7 执行
ANALYZE TABLE后仍慢?因为默认关闭直方图,需先设set global histogram_generation_enabled = on - PostgreSQL 中
ANALYZE不会更新pg_class.reltuples的精确值,它仍是估算值;真正精确行数得查SELECT COUNT(*) - 某些 ORM(如 Django 的
bulk_update)批量改完不触发ANALYZE,得在应用层补调用或加定时任务
统计信息不是越新越好,也不是越多越准——关键是让优化器对「最常被 WHERE / JOIN 用到的列」有合理分布认知。盲目全表高频 ANALYZE 可能拖慢系统,而漏掉关键列又会让执行计划崩盘。

















