使用Postgres v.8.4.2。
我有一个标准的三表设置,用于多对多关系。针对其中两个表编写的查询应该返回没有现有映射的单个记录:
SELECT b.id
FROM scm_branch b
LEFT OUTER JOIN "scm_branchgroup_branches" bgb
ON b.id = bgb.branch_id
WHERE
bgb.branch_id is NULL
LIMIT 1
(scm_branchgroup_branches是保存映射记录的三元表)
此查询具有以下顶级费用:
限制(成本= 0.00..0.22行= 1宽度= 4)
但是,如果我将WHERE条件中使用的字段更改为bgb表的主键,则成本会急剧上升:
SELECT b.id
FROM scm_branch b
LEFT OUTER JOIN "scm_branchgroup_branches" bgb
ON b.id = bgb.branch_id
WHERE
bgb.id IS NULL
LIMIT 1
(注意:此查询使用“bgb.id IS NULL”vs“bgb.branch_id is NULL”在前面的示例中使用)
顶级费用:
限制(成本= 236366.74..4644900.75行= 1宽度= 4)
为什么会出现如此剧烈的差异?我的意思是我看到了执行计划的差异,但我不明白差异的根本原因。
我很乐意提供回答此问题所需的任何其他信息。
由于 d。
答案 0 :(得分:1)
在branch_id IS NULL
的版本中,PostgreSQL认识到您正在进行反连接,并使用“哈希连接”类型算法进行相应的优化。 (Google PostgreSQL hash left anti-join
提供了有关此优化的大量信息。)但是,在id IS NULL
的版本中,它无法识别这一事实,并且其优化功能并不那么有用。更重要的是,连接基本上强制它使用branch_id
上的索引,因此它无法利用id
上的主键索引,并且必须参考实际的表数据来确定是否给定记录满足WHERE条款。
(可能还有其他因素在起作用 - 我不是PostgreSQL的专家 - 但我相信这些是主要因素。)