坏(相关)或良好(不相关)子查询?

时间:2017-01-24 11:16:20

标签: sql sql-server subquery correlated-subquery

我想知道,如果以下更新语句中的子查询是好的(不相关)还是坏的(子查询)?

换句话说,我的问题是,这是一个效率低下的查询吗?

UPDATE tableA
SET field1=0
FROM tableA
WHERE field2 IN (SELECT field2 
                 FROM tableA
                 WHERE someField IS NOT NULL 
                 AND someOtherField = 'ABC')

2 个答案:

答案 0 :(得分:1)

您的查询不相关,它只是一个子查询..

下面是一个相关的子查询..

UPDATE a
SET field1=0
FROM tableA a
WHERE exists  (SELECT 1
                 FROM tableB b
                 WHERE a.somecol=b.somecol)

相关子查询的另一个例子

select orderid,
(select custname from customers c where c.custid=o.custid) from orders o

以上查询可以写成连接

select orderid,custname
 from orders o
 join
 customers c
 on c.custid=o.custid

执行两个查询往往使用相同的执行计划,并且两者都具有相同的成本。因此我们不能假设,相关子查询不会表现更好

enter image description here

select orderid,
(select count(orderid) from orders o2 where o2.custid=o.custid ) 
from orders o

对于上面的相关子查询,SQL只能访问一次订单表并执行所有计算,它需要访问表两次..这只是我能看到的相关子查询

答案 1 :(得分:0)

子查询本质上不是好的或坏的(人们可能会争辩说SQL优化器是坏的,而不是子查询)。你的例子根本没有相关性。

特定查询是否有效的问题需要分析执行计划。反过来,这主要取决于数据的分布,索引和数据的分区方案。您的查询没有任何先验错误。

还有其他方法可以编写逻辑。我喜欢这个:

WITH toupdate as (
      SELECT a.*,
             SUM(CASE WHEN someField IS NOT NULL AND someOtherField = 'ABC' 
                      THEN 1 ELSE 0
                 END) OVER (PARTITION BY field2) as cnt
      FROM tableA a
     )
UPDATE toupdate
    SET field1 = 0
    WHERE cnt > 0;

这不是100%相同。一个区别是,这会像NULL一样处理field2值,就像任何其他值一样;您的版本永远不会更新NULL值。