Back to Blog
PostgreSQL 慢查询优化实战
2 min read
PostgreSQL 慢查询优化实战
PostgreSQL 慢查询的核心问题通常是索引未命中、统计信息过时或执行计划偏离预期。解决这类问题不需要重启服务,只需利用 EXPLAIN (ANALYZE, BUFFERS) 拿到真实执行计划,就能定位瓶颈并针对性修复。
第一步:定位慢查询
不要凭感觉猜哪条 SQL 慢。直接查系统视图,找出耗时最长的查询:
SELECT query, calls, mean_exec_time, total_exec_time
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;
如果不确定是否安装了 pg_stat_statements,先确认扩展已启用:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
第二步:分析执行计划
拿到可疑 SQL 后,用 EXPLAIN (ANALYZE, BUFFERS) 替换 SELECT 执行。关键看几项:
- Seq Scan:全表扫描,通常意味着缺索引
- Filter / Rows Removed:过滤掉了大量数据,说明谓词选择率低
- Heap Blocks:实际读取的数据页数量,过高说明 I/O 压力大
示例输出解读:
Seq Scan on orders (cost=0.00..15800.00 rows=1 width=100)
Filter: (created_at > '2023-01-01')
Rows Removed by Filter: 999000
这里扫描了 100 万行,只留下 1 行,典型的全表扫描浪费。
第三步:创建合适索引
针对上面的例子,加一个局部索引即可:
CREATE INDEX idx_orders_created_at
ON orders (created_at)
WHERE created_at >= '2023-01-01';
注意:索引列的顺序很重要。如果是复合查询,把等值条件列放前面,范围条件列放后面。
常见错误:盲目加索引
很多开发者一看到慢查询就加索引,结果导致写入性能下降、空间膨胀。正确的做法是:
- 先确认查询是否真的走了索引
- 检查统计信息是否最新
- 再考虑是否需要调整索引策略
统计信息过期问题
PostgreSQL 依赖统计信息决定执行计划。如果刚插入大量数据,统计信息可能滞后。手动更新:
ANALYZE orders;
或者调大相关表的统计目标,让分析更精细:
ALTER TABLE orders ALTER COLUMN created_at SET STATISTICS 1000;
ANALYZE orders;
参数调优参考
如果确认索引和统计信息都没问题,再考虑数据库参数。重点看这几个:
effective_cache_size:建议设为内存的 50%-75%random_page_cost:SSD 上可降为 1.1work_mem:查询临时排序/哈希空间,不宜过大
修改参数后记得重启或 reload:
SELECT pg_reload_conf();
后续深入
了解 PostgreSQL 的执行器内部机制,能帮你预判优化效果。推荐阅读官方文档中关于「查询规划器」的章节,理解它如何权衡不同访问路径。