为什么我的不相关的子查询这么慢?

时间:2017-02-10 09:06:56

标签: sql sql-server performance sql-server-2016

我的声明需要 10秒才能对表X中的10k项目执行:

版本1

SELECT * 
FROM X 
WHERE pk = 77843 
  AND (a IS NULL OR a NOT IN (SELECT DISTINCT(b) 
                              FROM X
                              WHERE pk = 77843
                                AND l IS NOT NULL))

子查询是不相关的,这意味着它没有引用外部查询。这意味着子查询只应执行一次。

版本2:

现在,如果我提取子查询并预先执行计算,则查询将在< 1s。

DECLARE @listOfb table (id int)

INSERT INTO @listOfb(id) 
    (SELECT DISTINCT(b) as Numbers 
     FROM X
     WHERE pk = 77843
       AND l IS NOT NULL)

SELECT * 
FROM X 
WHERE pk = 77843 
  AND (a IS NULL OR a NOT IN (SELECT * FROM @listOfb))

那么为什么版本2比版本1快得多?

更新

我添加了(我认为所谓的)版本1的执行计划: 该查询正在删除大约10k行。

enter image description here

2 个答案:

答案 0 :(得分:1)

尝试使用公用表表达式和UNION:

;WITH CTE
AS
(
   SELECT * 
   FROM X 
   WHERE pk = 77843 
)
SELECT *
FROM CTE
WHERE a IS NULL
UNION ALL
SELECT *
FROM CTE C1
WHERE a IS NOT NULL AND 
      NOT EXISTS (SELECT * FROM CTE C2 WHERE C1.a = C2.b AND l IS NULL)

答案 1 :(得分:1)

您应该查看此article

我没有相同的服务器版本,但我想尝试的是解锁x'在主查询上还有子查询。

SELECT * 
FROM X (NOLOCK)
WHERE pk = 77843 

根据我的小经验,取决于表格大小及其上的索引,我发现有时会在同一个表格中查询两次时的性能差异(特别是在条件相同的情况下' pk = 77843'和/或更新/删除操作)。

关于你的上一条评论。我从执行计划中看不到多次执行子查询的情况。在我看来,第一个index_seek锁定pk列[主查询],并在同一列上到达第二个index_seek [子查询]时(我猜我可以& #39; t看到屏幕截图中的所有细节,导致性能问题。

但是,当你分别执行这两个查询(条件几乎相同)时,你会有更好的表现。