PostgreSQL 15 中,Parallel Index Scan 可以参与 JOIN,但仅限于内表且满足特定条件时。它不会出现在外表扫描中,仅在 Hash Join 或 Merge Join 的内表阶段,且索引足够大、选择性好、成本估算合理时才启用。

并行Index Scan在JOIN中到底起不起作用
直接说结论:PostgreSQL 15 中,Parallel Index Scan 可以参与 JOIN,但**仅限于内表(inner relation)且满足特定条件时**。它不会出现在外表(outer relation)上,也不会在 Nested Loop 的外表扫描中启用——哪怕外表也建了索引。优化器只会在 Hash Join 或 Merge Join 的内表扫描阶段,且该表足够大、索引选择性好、成本估算合理时,才考虑并行索引扫描。
为什么EXPLAIN里看不到Parallel Index Scan节点
常见现象是:明明对 JOIN 条件列建了索引,EXPLAIN (ANALYZE, VERBOSE) 却只显示 Index Scan,没有 Parallel Index Scan。原因通常有三个:
-
max_parallel_workers_per_gather设为 0 或太小(如仍用默认值 2),而当前查询的并行成本估算未触发并行计划 - 内表实际大小小于
min_parallel_index_scan_size(默认 512kB),比如索引块只占几百 KB,系统认为“不值得并行” - JOIN 类型是 Nested Loop,且外表不是小表——此时优化器倾向让外表驱动、内表走单线程索引查找,避免为每次外表行都拉起并行 worker
让Parallel Index Scan真正跑起来的关键配置
要让 JOIN 中的内表启用并行索引扫描,必须同时满足参数、数据和计划三方面条件:
- 调高
max_parallel_workers_per_gather至 4~6(不能 ≥8,否则单查询易耗尽work_mem) - 确认
min_parallel_index_scan_size≤ 内表索引实际大小(可用pg_total_relation_size('idx_table_col')查) - 强制引导优化器选 Hash Join 或 Merge Join:在 JOIN 条件列上建联合索引(如
CREATE INDEX idx_orders_user_status ON orders (user_id, status)),并确保两表统计信息最新(ANALYZE orders, payments) - 避免在 JOIN 条件中使用函数或类型转换,否则索引失效,自然也谈不上并行扫描
容易被忽略的资源陷阱
并行索引扫描看似轻量,但它每个 worker 都会独立申请 work_mem,并可能触发额外的 buffer pin 竞争。最常踩的坑是:
- 把
max_parallel_workers_per_gather设成 8,而work_mem是 64MB → 单个 JOIN 查询最多吃掉 512MB 内存,多个并发就 OOM - 在高并发 OLTP 场景下开启并行,导致大量短查询争抢并行 worker 槽位,反而拖慢整体响应
- 误以为“只要建了索引就自动并行”,忽略了
parallel_setup_cost和parallel_tuple_cost对成本模型的影响——它们默认偏保守,需酌情调低(如设为 50 和 0.02)才能让优化器更愿意选并行计划

















