使用相关子查询

时间:2014-02-27 12:15:44

标签: sql sql-server sql-server-2008

假设在列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.

2 个答案:

答案 0 :(得分:2)

如果t_right包含NULL,则可以返回不同的结果。

NOT IN (x, y, NULL)始终返回空集,但等式谓词会隐式排除NULL中的任何t_right

如果t_left包含NULLt_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的评论非常有趣,因为两个查询不一样,除非val1t_right中的主键。