假设在列val1上索引了2个表t_left和t_right 他们在val1上随机分配了100000条记录 我有2个选项可以从t_right中不存在的t_left中提取记录:
1.SELECT *
FROM t_left o
WHERE o.val1 not in (Select val1
FROM t_right h)
2.SELECT *
FROM t_left o
WHERE o.val1 not in (Select val1
FROM t_right h
where h.val1 = o.val1)
令人惊讶的是,我看到两种方法都有相同的执行计划 这些只是语法上的怪癖;或者它们确实有独特的合适用例吗? 我使用的是sql server 2008.
答案 0 :(得分:2)
如果t_right
包含NULL
,则可以返回不同的结果。
NOT IN (x, y, NULL)
始终返回空集,但等式谓词会隐式排除NULL
中的任何t_right
。
如果t_left
包含NULL
且t_right
非空,则他们可以返回不同的结果。
NULL NOT IN (...)
(...)
为空集,否则永远不会为真,因此左侧的任何NULL
仅在t_right
完全为空或第二次查询时保留。
如果两列都不可为空,则两个查询都具有相同的语义,并且可能具有相同的计划。
答案 1 :(得分:0)
两个查询计划相同的原因(至少在执行计划的级别)是因为这两个查询具有一定的等效性。
进行第一个查询:
SELECT *
FROM t_left o
WHERE o.val1 not in (Select val1 FROM t_right h);
SQL Server可以执行此查询的一种方法是使用t_right.val1
上的索引。换句话说,查询执行如下:“在val1
的索引中查找t_left
中的每个t_right.val1
。如果找不到,请接受记录。”
第二个查询将相关性添加到:
SELECT *
FROM t_left o
WHERE o.val1 not in (Select val1 FROM t_right h WHERE h.val1 = o.val1);
猜猜是什么? 完全相同的执行方法可以适用于此查询。相关性只会使索引查找更加明确。
顺便说一下,还有另一种表达此查询的方法:
SELECT *
FROM t_left o
WHERE not exists (Select val1 FROM t_right h WHERE h.val1 = o.val1);
我的猜测是,这也有相同的执行计划。
Martin的评论非常有趣,因为两个查询不一样,除非val1
是t_right
中的主键。