I
Member
PostgreSQL 一条查询突然从几十毫秒变成几秒,很多人上来就加索引,结果越加越慢。慢查询排查要先看执行计划,再决定是索引问题、统计信息问题还是写法问题,顺序错了全是无用功。
第一步一定是 EXPLAIN ANALYZE,看实际行数和预估行数的差距。预估差一个数量级以上,先怀疑统计信息过期,跑 ANALYZE 再看,不要急着建索引。第二步看扫描方式:Seq Scan 不一定是坏事,小表全表扫比走索引更快;但大表 Seq Scan 且过滤后行数很少,就是缺索引的信号。第三步看连接方式,Nested Loop 在驱动表行数大时会爆炸,Hash Join 反而更稳,这时要检查连接字段类型是否一致,类型不一致会导致索引失效。第四步看排序和聚合,Sort 节点后面如果跟着很大的行数,可能是缺复合索引,或者 work_mem 太小导致落盘。
索引重建只在确认索引本身有问题时做:膨胀严重的索引可以 REINDEX,但要在业务低峰做;不要因为一次慢查询就把单列索引改成一堆复合索引,写放大和维护成本会反噬。还有一个常见坑:查询里写了函数包裹字段,比如 lower(name),普通索引用不上,要建表达式索引才行。
你们排查慢查询时,是先看执行计划还是先看慢日志里的锁等待?有没有遇到过统计信息过期导致的误判?
第一步一定是 EXPLAIN ANALYZE,看实际行数和预估行数的差距。预估差一个数量级以上,先怀疑统计信息过期,跑 ANALYZE 再看,不要急着建索引。第二步看扫描方式:Seq Scan 不一定是坏事,小表全表扫比走索引更快;但大表 Seq Scan 且过滤后行数很少,就是缺索引的信号。第三步看连接方式,Nested Loop 在驱动表行数大时会爆炸,Hash Join 反而更稳,这时要检查连接字段类型是否一致,类型不一致会导致索引失效。第四步看排序和聚合,Sort 节点后面如果跟着很大的行数,可能是缺复合索引,或者 work_mem 太小导致落盘。
索引重建只在确认索引本身有问题时做:膨胀严重的索引可以 REINDEX,但要在业务低峰做;不要因为一次慢查询就把单列索引改成一堆复合索引,写放大和维护成本会反噬。还有一个常见坑:查询里写了函数包裹字段,比如 lower(name),普通索引用不上,要建表达式索引才行。
你们排查慢查询时,是先看执行计划还是先看慢日志里的锁等待?有没有遇到过统计信息过期导致的误判?