我有一個很大的查詢,其中一個簡單的子查詢優化從8分鐘下降到20秒。我不確定我明白爲什麼優化會產生如此激烈的效果。爲什麼這個(不相關的)子查詢導致這樣的問題?
從本質上說,這裏的問題部分:
SELECT (bunch of stuff)
FROM
a LEFT OUTER JOIN b ON a.ID = b.a
LEFT OUTER JOIN c ON b.ID = c.b
...
...
INNER JOIN veryLargeTable
ON a.ID = veryLargeTable.a
AND veryLargeTable.PetID =
(SELECT id from Pets WHERE Pets.Name = 'Something') /* BAD! */
...
...
在所有的,有16個連接的表。如果我更換veryLargeTable
的第二謂詞與含有petID(而不是使用子查詢)預填充的變量加入整個查詢加快急劇:
AND veryLargeTable.PetID = @petID /* Awesome! */
顯然,當正在執行(SELECT id from Pets WHERE Name = 'Something')
爲每一行。有兩件事我不完全明白:
據我所知,這是一個不相關的子查詢。 Pets表根本不是外部查詢的一部分。是不是非相關的子查詢獨立評估(並因此優化)?爲什麼這裏不是這種情況?
執行計劃顯着不同。在上面的失敗案例中,整個子樹處理估計的950k行。在win情況下(使用變量而不是子查詢),估計的行只有大約125k。這是怎麼回事?爲什麼有更多的行涉及如果該子查詢在那裏? Pets.Name列肯定有唯一的數據(但據我所知,沒有唯一的約束)。
請注意,將謂詞移至WHERE子句不會影響查詢,正如我所期望的那樣,因爲它是INNER JOIN。
深入瞭解!
使用變量可能導致不同的計劃。它通常會導致更糟糕的計劃,因爲變量的值在編譯時並不知道。也許你在這個場合很幸運。也許專注於實際計劃中的估計行數與實際行數,以查看是否有任何可能的統計問題。當您查看緩慢運行的實際執行計劃時,您是否可以看到多次執行的子查詢? – 2010-08-26 17:29:33
@Martin Smith - 我可以看到正在執行的查詢作爲索引查找,並將其作爲其他輸入放入帶有RID查找的嵌套循環中。這是非常低的成本 - 但令人驚訝的是,進一步的一些操作,它將它推到哈希匹配與非常大表中的集羣索引掃描,這是一個巨大的成本。在查詢的好版本中 - 這些操作都不存在。 – womp 2010-08-26 17:52:43