2017-02-10 68 views
2

我有需要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

+3

你看過**執行計劃**的兩個查詢嗎? –

+0

'DISTINCT'不是一個函數(在列上),它是'SELECT DISTINCT'的一部分,適用於整個選定的行。刪除那些冗餘括號以使事情更清晰! 'SELECT DISTINCT(a),b ...'最好寫爲'SELECT DISTINCT a,b ...',但也可以寫爲'SELECT DISTINCT a,(b)...' – jarlh

+1

,不需要在這裏執行SELECT DISTINCT ... – jarlh

回答

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

不需要第一個Select,'NOT EXISTS'無論如何都會返回帶有'a'中的NULL的行。 – dnoeth

1

你應該看看這個article

我沒有在同一臺服務器的版本,但我會嘗試解除主查詢中的'從x',但也在子查詢上解鎖。

SELECT * 
FROM X (NOLOCK) 
WHERE pk = 77843 

從我的一點經驗,取決於表的大小和它的索引,我發現有時性能上的差異,而查詢兩次相同表(特別是與相同條件「PK = 77843」和/或更新/刪除操作)。

關於您的最新評論。我沒有從執行計劃中看到多次執行子查詢的位置。在我看來,第一個index_seek鎖定了pk列[主要查詢],並且當到達同一列上的第二個index_seek [子查詢](我猜因爲我看不到屏幕截圖中的所有細節)這會導致性能問題。

但是,這樣做的原因是,當您單獨執行這兩個查詢(具有幾乎相同的條件)時,性能會更好。