查询优化与执行计划
数据库优化器会为每条 SQL 选择一条执行路径。学会读懂执行计划,就能定位「为什么这条查询慢」。
优化器的代价模型
优化器基于统计信息(行数、索引基数、数据分布直方图)估算每种执行方式的代价,选择代价最低的方案。因此:
- 统计信息过期会导致选错索引 —— 定期
ANALYZE。 - 复杂查询(多表连接)的搜索空间巨大,优化器可能做出次优选择。
- 优化器的目标是「估算代价最小」,不总是「实际最快」。
读懂 EXPLAIN
type 的性能排序(由差到好):
Tip
Extra 中出现 Using filesort 或 Using temporary 往往意味着额外排序/临时表,是重点优化对象。出现 Using index 则说明命中了覆盖索引,是理想状态。
定位慢查询
PostgreSQL 使用 EXPLAIN ANALYZE 展示实际耗时,注意区分预估行数与实际行数:
常见优化手段
- 补索引 / 改联合索引:让关键查询走
range或ref,避免ALL。 - 消除回表:用覆盖索引满足高频查询。
- 改写 SQL:避免函数作用于索引列;用
JOIN替代相关子查询。 - 控制结果集:加
LIMIT、分页时避免大OFFSET(改用游标/键集分页)。 - 减少排序:让
ORDER BY与索引顺序一致,避免 filesort。 - 拆分大查询:把复杂报表拆成预聚合表或异步任务。
- 调整连接顺序与统计信息:必要时
ANALYZE TABLE或加 Hint。
Warning
不要盲目加 FORCE INDEX。强制索引在数据分布变化后可能反而更慢,应优先修正统计信息与索引设计。优化前务必用真实数据量测量,避免「小表上的结论」误导。
分页、批量与拉取大小
- 深分页是经典性能陷阱,键集分页(Keyset Pagination)几乎总是更优。
- 批量写入用多值
INSERT或批量接口,减少网络往返。 - 大结果集应流式处理,避免一次性加载到内存。
小结
- 优化器基于统计信息估算代价,统计过期会选错计划。
EXPLAIN的type、key、rows、Extra是定位问题的第一现场。- 优化优先级:索引 → SQL 改写 → 结构/架构调整。
- 一切优化以真实数据与测量的结果为准。