遇到慢查询,最常见的第一反应是“加索引”。这有时有效,却也容易掩盖真正的问题:返回数据过多、过滤条件选择性太低、统计信息失真,或接口本身正在完成一个不适合在线执行的任务。
一、先保留现场
分析前记录 SQL 模板、绑定参数、执行时长、调用来源、返回行数和发生频率。同一句 SQL 在不同参数下可能产生完全不同的计划,只看脱敏后的模板往往会错过数据倾斜。
在可控环境中使用 EXPLAIN (ANALYZE, BUFFERS),它会真实执行语句。对写操作或超大查询,应先在副本或事务保护下验证,避免分析动作本身影响生产。
二、阅读计划不只看成本
- 比较预估行数与实际行数,差距过大通常指向统计信息或数据相关性问题。
- 关注循环次数;一个看似便宜的节点执行几十万次,累计成本会很高。
- 区分缓存命中与磁盘读取,并检查排序、哈希是否溢出到临时文件。
- 从最内层耗时节点向外看,找到数据被放大的位置。
actual rows 120,438 / estimated rows 240
loops 8,912
Buffers: shared hit=18420 read=7321
loops 8,912
Buffers: shared hit=18420 read=7321
这些数字比“是否走索引”更有信息量。顺序扫描小表完全合理;相反,一个选择性很差的索引可能带来大量随机读取,甚至比顺序扫描更慢。
三、回到访问模式与数据分布
确认接口真正需要什么:是否必须返回全部列,是否需要精确总数,分页是否使用越来越昂贵的偏移量,时间范围是否可以限制。很多优化来自减少工作量,而不是让数据库更快地完成不必要的工作。
多列条件需要按真实过滤和排序顺序设计复合索引;强相关字段可考虑扩展统计信息;历史数据持续增长时,可以按访问模式评估分区,但不应把分区当成自动提速开关。
四、验证整体收益
优化后不仅要比较单次耗时,还应观察吞吐、CPU、缓存命中、锁等待和写入成本。新增索引会占用存储并拖慢写入,缓存升温后的测试也可能高估收益。
好的查询优化会同时解释:为什么变快、代价是什么、数据增长后还能维持多久。
最后把慢查询与具体调用链关联起来,并设置基于分位数和频率的观察机制。偶发的 2 秒后台报表,与每秒执行数百次的 80 毫秒查询,优先级并不相同。
最后更新:2026 年 7 月 12 日
← 返回文章列表