是,autovacuum 会自动触发 analyze,但依赖变更行数占比和上次统计时间,由 autovacuum_analyze_threshold 和 autovacuum_analyze_scale_factor 共同决定,默认为 50 行 + 10% 表行数。

autovacuum 会自动触发 ANALYZE 吗?
会,但不是每次写入都触发,也不是固定时间间隔。它依赖表的变更行数占比和上次统计时间,由 autovacuum_analyze_threshold 和 autovacuum_analyze_scale_factor 共同决定。
默认值是:阈值 50 行 + 比例 10%(即 50 + 当前表总行数 × 0.1)。小表(比如只有 200 行)改 70 行就满足条件;大表(1000 万行)得改满 100 万行才可能触发。
- 如果业务频繁更新小维度表(如
status_codes),默认配置下 ANALYZE 可能长期不跑,导致执行计划劣化 -
autovacuum_analyze_scale_factor = 0可禁用比例项,只看绝对变更量,适合变动频繁的小表 - 修改后需连接到对应数据库执行
ALTER TABLE ... SET (autovacuum_analyze_scale_factor = 0),全局参数只影响新表
手动 ANALYZE 要不要加 VERBOSE?
日常维护不用,VERBOSE 只在排查统计偏差时临时启用,它会输出每列采样行数、实际 distinct 值数量等调试信息,但不改变行为,也不提升精度。
典型误用场景:把 ANALYZE VERBOSE 当“更彻底的统计”来定期跑——其实和普通 ANALYZE 用的是同一套采样逻辑,只是多打几行日志。
-
ANALYZE默认对每列采样约 300 行(受default_statistics_target影响),并非全表扫描 - 想提高某列统计质量,应单独设置:
ALTER TABLE t ALTER COLUMN c SET STATISTICS 1000 - VERBOSE 输出里出现
"sample block" = N表示实际读了 N 个数据页,可用于判断是否因数据稀疏导致采样不足
VACUUM ANALYZE 和分开执行 ANALYZE 有啥区别?
前者先做 VACUUM(清理死元组、更新可见性映射),再做 ANALYZE;后者只更新统计信息。两者不等价,也不能互相替代。
常见错误是以为 VACUUM ANALYZE “更全面”,结果在高并发更新的表上频繁执行,反而引发 I/O 尖峰和锁等待。
-
VACUUM阶段会持有ShareUpdateExclusiveLock,阻塞CREATE INDEX、ALTER TABLE等操作 - 如果只是因为执行计划变差而怀疑统计过期,优先跑
ANALYZE,不是VACUUM ANALYZE - 对只读大表(如数仓事实表),可以禁用 autovacuum(
autovacuum_enabled = off),但必须定期手动ANALYZE,否则优化器永远看不到新分区的数据分布
统计信息不准时,EXPLAIN 显示的 rows 和实际相差十倍以上怎么办?
先确认是不是采样不足或数据倾斜导致,而不是立刻调大 default_statistics_target。盲目设成 1000 或 5000 容易让 ANALYZE 变慢、占用更多 shared_buffers,并不能解决根本问题。
PostgreSQL 的统计直方图只存最常见值(MCV)和等宽直方图,遇到长尾分布(比如用户积分从 0 到 1 亿)、或大量 NULL 值,就容易误判。
- 用
SELECT * FROM pg_stats WHERE tablename = 't' AND attname = 'c'查看n_distinct和most_common_vals是否合理 - 如果某列 NULL 占比超 30%,考虑建部分索引:
CREATE INDEX idx ON t(c) WHERE c IS NOT NULL,并确保 WHERE 条件里也写明c IS NOT NULL - 对时间戳字段,按月分区后,每个子表单独
ANALYZE比在父表上跑一次更有效
统计信息不是越新越好,也不是越多越好;关键是在变更敏感点及时触发,且采样能覆盖真实分布形态。很多人卡在“不知道该信哪一行数字”,其实应该先信 pg_stats 里的 histogram_bounds,再对照业务逻辑看它是否真的漏掉了关键分界点。










