资讯动态

PostgreSQL 慢查询定位:用 EXPLAIN ANALYZE 揪出索引失效,耗时从 2.1s 降到 12msPostgreSQL

发布时间:2026/10/26 18:44:55 来源:尧图企业网站定制
TL;DR一条本应走索引的查询跑了 2.1 秒排查后发现是函数包裹索引列导致索引失效。用EXPLAIN ANALYZE定位后改写查询条件耗时降到 12ms提升 175 倍。现象查询突然变慢某天业务反馈订单列表页加载要 2 秒多。查看慢查询日志发现一条高频 SQLSELECT * FROM orders WHERE date(created_at) 2025-03-01 ORDER BY id DESC LIMIT 20;orders 表有 500 万行created_at上有普通 B-tree 索引。之前一直正常最近数据量涨了开始变慢。定位EXPLAIN ANALYZE 揭真相直接跑EXPLAIN ANALYZE看执行计划EXPLAIN ANALYZE SELECT * FROM orders WHERE date(created_at) 2025-03-01 ORDER BY id DESC LIMIT 20;关键输出Seq Scan on orders (cost0.00..102432.80 rows523 width96) (actual time0.045..2108.234 rows523 loops1) Filter: (date(created_at) 2025-03-01::date) Rows Removed by Filter: 4999477 Planning Time: 0.123 ms Execution Time: 2108.456 ms看到Seq Scan全表扫描说明索引没被用上。原因就是date(created_at)这个函数包裹了索引列导致索引失效。修复改写查询让索引生效把函数放到条件右边用范围查询代替函数调用SELECT * FROM orders WHERE created_at 2025-03-01::date AND created_at 2025-03-02::date ORDER BY id DESC LIMIT 20;再次EXPLAIN ANALYZE结果Limit (cost0.43..2.65 rows20 width96) (actual time0.012..0.187 rows20 loops1) - Index Scan Backward using orders_created_at_idx on orders (cost0.43..57730.72 rows523 width96) (actual time0.011..0.184 rows20 loops1) Index Cond: ((created_at 2025-03-01::date) AND (created_at 2025-03-02::date)) Execution Time: 0.201 ms实际执行时间从 2108ms 降到 0.2ms如果算上网络开销业务侧感知从 2.1s 降到 12ms因为原来还有数据传输时间。复盘为什么函数会让索引失效B-tree 索引存储的是列原始值的排序结构当你对列做函数运算时数据库无法直接利用索引中的排序只能对每一行计算函数值再过滤这就是全表扫描的根源。常见坑还有WHERE upper(name) ABC、WHERE id 1 100等。解决方案要么改写查询如上要么建表达式索引如CREATE INDEX ON orders (date(created_at))但后者增加写开销不如前者干净。照做路径发现慢查询先看执行计划EXPLAIN ANALYZE your_sql。如果看到Seq Scan且过滤条件里有函数优先改写 SQL。把函数移到条件右侧用范围查询或等值查询替代。无法改写时再考虑表达式索引。下一步去你的慢查询日志里搜一下有没有类似WHERE func(col) ...的语句用今天的方法改掉预计能提速百倍。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑