← 中文资源

简体中文版本

EXPLAIN ANALYZE 索引使用诊断

用 EXPLAIN ANALYZE 加 BUFFERS 诊断慢查询:读扫描类型与真实行数、比对预估偏差定位过期统计、验证新索引被采用。

阅读英文原文

示例说明

EXPLAIN 只显示预估计划,ANALYZE 才执行并附上每步的真实行数与耗时——预估与实际的偏差本身就是线索:偏差数倍说明统计信息过期,优化器在盲选计划。BUFFERS 再加一层磁盘 IO 真相——shared hit 与 read 的比例揭示缓存命中率,热点数据与冷数据的性能差异由此解释。

技术要点

  • ANALYZE 附带每算子的真实行数
  • BUFFERS 揭示缓存与磁盘比例
  • 预实偏差指向过期统计信息

代码解读

主查询展示联表计划的全貌:扫描方式、联结策略、排序节点层层展开,LIMIT 截断在计划树上可见;第二个查询对比统计刷新前后的行数估算;最后建复合索引并验证查询计划切换为索引扫描——索引是否真被采用只能由计划证实,不能靠直觉。

使用建议

ANALYZE 会真实执行,生产慢查询在从库或限流后跑。行数估算的 n_distinct 直方图可手动调整。语句级计时参数 track_io_timing 需要开启才有精确 IO。

代码示例

-- BUFFERS 选项显示磁盘与缓存命中,真实成本的核心
EXPLAIN (ANALYZE, BUFFERS)
SELECT o.id, c.email
FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE o.status = 'paid'
  AND o.created_at >= '2026-10-01'
ORDER BY o.created_at DESC
LIMIT 50;

-- 检查估算偏差:预估行数与实际行数差距大时统计信息过期
EXPLAIN (ANALYZE)
SELECT count(*)
FROM orders
WHERE customer_id = 42;

-- 统计信息刷新后重测
ANALYZE orders;
EXPLAIN (ANALYZE)
SELECT count(*)
FROM orders
WHERE customer_id = 42;

-- 验证新索引被采用:Index Scan / Index Only Scan
CREATE INDEX CONCURRENTLY idx_orders_customer_status
  ON orders (customer_id, status);

EXPLAIN (ANALYZE)
SELECT id FROM orders
WHERE customer_id = 42 AND status = 'paid';