You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL:直接用ID查询成本低,子查询取ID后查询为何成本极高?

PostgreSQL子查询合并后查询成本飙升的原因

在PostgreSQL 13.10与13.14版本中,直接在查询中硬编码ID值时,查询成本极低:

-- Query 1.
-- Nested Loop Semi Join  (cost=2.27..280.78 rows=1 width=129)
EXPLAIN SELECT *
FROM view_companies_extra
WHERE company_id IN (
  SELECT id
  FROM companies
  WHERE id = 'cddba3ad-dd13-48bb-a5b0-f0e325f27d51'
);

但通过子查询动态获取ID后再执行查询时,成本却大幅升高:

-- Query 2.
-- Seq Scan on companies  (cost=0.00..18581.05 rows=1 width=16)
--  Filter: ((number)::text = '7731394650'::text)
EXPLAIN SELECT id
FROM companies
WHERE number = '7731394650';

-- Query 3.
-- Nested Loop  (cost=3.10..10324011.11 rows=12 width=129)
EXPLAIN SELECT *
FROM view_companies_extra
WHERE company_id IN (
  SELECT id
  FROM companies
  WHERE number = '7731394650'
);

单独执行Query2获取ID后代入Query1执行速度很快,但合并为Query3时却耗时极久,核心原因如下:

  • 统计信息传递与行数估算偏差
    Query1中,子查询基于主键id精确匹配,优化器能直接确定子查询仅返回1行,因此选择高效的Nested Loop Semi Join,并将company_id = 'xxx'的条件下推到视图view_companies_extra的底层表,利用索引快速定位数据。而Query3中,虽然Query2估算子查询返回1行,但优化器无法将这个估算结果准确传递到外层查询——它可能错误假设子查询会返回更多行(依赖number列统计信息判断基数),导致按多行匹配逻辑生成计划,嵌套循环的执行次数被大幅高估,成本飙升。

  • 视图条件下推失败
    view_companies_extra作为视图,Query1的常量ID条件可以直接下推到视图的底层表查询,避免全量扫描视图数据。但Query3中,子查询返回的是动态ID集合,优化器无法将IN子查询的条件下推到视图内部,导致视图先被全量扫描,再和子查询结果做关联,触发大量不必要的数据扫描,耗时剧增。

  • 执行计划的连接类型差异
    Query1使用Nested Loop Semi Join,这种连接在子查询结果集极小时效率极高;但Query3中优化器选择了普通Nested Loop而非半连接——半连接会在匹配到第一条数据后停止扫描,普通连接则会遍历所有可能的匹配行,进一步增加执行成本。

另外,number列未创建索引也是潜在诱因:Query2的全表扫描虽因返回行数少单独执行速度快,但优化器会认为这个子查询的执行成本较高,进而影响外层查询的计划选择。


内容的提问来源于stack exchange,提问作者Maxim Mandrik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 10:05:15