Skip to content

查询优化与执行

代价优化器、EXPLAIN 阅读、三种连接算法、并行查询、统计信息。

Updated View as Markdown
For humans

查询优化与执行

PostgreSQL 的优化器是代价优化器:为每条 SQL 枚举可能的执行路径,按估算代价选最便宜的。理解代价模型,才知道执行计划为什么长这样,以及怎么调。

代价模型

每条路径都有估算代价(cost 单位,不是毫秒):

  • 顺序扫描:seq_page_cost(默认 1.0)乘页数
  • 索引扫描:random_page_cost(默认 4.0)乘页数加索引遍历
  • CPU 代价:cpu_tuple_cost

代价估算的输入是统计信息:ANALYZE 收集的每列分布、相关性、NULL 比例。统计信息不准,代价模型再精细也是错的方向。“先查统计,再查计划”是 PG 优化的第一原则。default_statistics_target 控制采样精度,关键列可调大。

执行计划怎么读

EXPLAIN (ANALYZE, BUFFERS) SELECT ...

阅读顺序:

  1. 从叶子(扫描节点)往根读
  2. 对比 estimated rows 和 actual rows,找第一处大的估算偏差。偏差会沿连接逐层放大,改变连接顺序和算法
  3. 看每个节点的 loops(嵌套循环内层会执行多次,实际行数要乘 loops)
  4. 看 BUFFERS 的命中(hit)和读取(read)判断是否吃缓存

常见节点:

节点 含义 关注点
Seq Scan 顺序扫描 小表或低选择性时合理
Index Scan 索引扫描 是否用了对的索引
Index Only Scan 仅索引扫描 依赖可见性映射
Bitmap Scan 位图扫描 多个索引组合
Nested Loop 嵌套循环 内层 loops 次数
Hash Join 哈希连接 hash 内存是否落盘
Merge Join 归并连接 两侧是否有序

三种连接算法

  • Nested Loop:外层每行去内层找,适合小表驱动大表、内层走索引
  • Hash Join:小表建哈希,大表探测,适合无索引的大连接
  • Merge Join:两侧按连接键排序后归并,适合已有序或等值连接

优化器根据行数估算选,work_mem 不足时 Hash Join 会落盘(临时文件),是常见性能瓶颈。

并行查询

PG 支持查询级并行:计划中出现 Gather/Gather Merge 节点,多个 worker 并行扫描。收益最大的场景是“访问大量数据、返回少量行”的分析查询。三个相关参数:max_parallel_workers_per_gather(单查询并行度)、max_parallel_workers(全局)、max_worker_processes(总进程上限)。OLTP 小查询不建议并行,启动 worker 的开销大于收益。

面试追问

  1. 代价优化器怎么工作? 枚举执行路径按估算代价选最便宜。代价基于页数和 CPU 成本的加权,输入是统计信息
  2. EXPLAIN ANALYZE 看什么? 对比估算行数和实际行数找偏差,偏差沿连接放大。先修统计信息再调 SQL
  3. 三种连接算法怎么选? 小表驱动大表用 Nested Loop,无索引大连接用 Hash Join,两侧有序用 Merge Join
  4. 统计信息不准怎么办? ANALYZE 更新,调大 default_statistics_target,对关键列做扩展统计。统计错了优化器选什么计划都是错的
  5. 并行查询什么时候有效? 大表扫描返回少量行。小查询并行开销大于收益,OLTP 不要开
Navigation

Type to search…

↑↓ navigate↵ selectEsc close