2011-10-12 34 views
0

我只是認爲,我的查詢:如何重寫查詢以適應羣集索引?

SELECT X.A, X.B, X.GroupName 
FROM TableA X 
INNER JOIN TableB Y -- Huge table 
ON (X.A = Y.Name OR X.B = Y.Name) 

TableBCLUSTERED INDEX ON列Name因爲它的這個查詢正在採取小時運行。所以我所做的是將這個查詢重寫爲:

SELECT X.A, X.B, X.GroupName 
FROM TableA X 
INNER JOIN TableB Y -- Huge table 
ON X.A = Y.Name 
UNION 
SELECT X.A, X.B, X.GroupName 
FROM TableA X 
INNER JOIN TableB Y -- Huge table 
ON X.B = Y.Name 

這個在幾秒鐘內運行,或者在最壞的情況下運行幾分鐘。儘管我在理解了自己的理由後明白了理由,但我想知道是否有更簡潔的方式來編寫此查詢。我正在考慮一個CTE,但然後ON X.A = Y.NameON X.B = Y.Name就像參數,我不知道如何處理這個。

我的實際查詢非常大,所以我想避免重複兩次以獲得UNION。有什麼建議麼?

回答

2

在這種情況下,如果兩個條件需要以不同方式使用索引,則可以使用UNION。通過將它們作爲OR在單個條件中,您可能會刪除使用索引的功能。

這是一樣的問題:

SELECT MIN(myCol), MAX(myCol) 

通過包括兩個,因爲它試圖找到「兩全其美」查詢,你可能會borking查詢計劃的使用索引,而不是「最好每個世界的,單獨,加在一起」

這裏是一個(過時)鏈接,說明了我的觀點:
http://code.cheesydesign.com/?p=279
http://richardfoote.wordpress.com/category/index-full-scan-minmax/

+0

+1謝謝。這些鏈接很有幫助!那麼我會堅持下去。我想知道 - 是否有寫這個查詢的緊湊方式(如使用CTE或類似的東西)還是我重複我的查詢兩次? – Legend

+0

你不應該用MS SQL Server來做這件事。我看到這兩篇文章都是針對Oracle的,當我在SQL Server的一個大型(174M行)表上執行最小和最大值時,查詢計劃顯示兩個執行路徑並幾乎立即返回結果。 –

+0

@JasonGoemaat OP表示這不是他真正的查詢。如果不檢查實際的查詢計劃,那麼確定他是否有效使用索引並不是一個好方法。由於一些奇怪的查詢結構,是否可以阻止MSSQL使用索引。 – Matthew

1

您可以嘗試更新統計信息,有時可幫助查詢選擇合適的索引,特別是如果您在一段時間內沒有這樣做並插入或更新了大量數據。

UPDATE STATISTICS TableB 

您也可以嘗試使用optimizer hint

SELECT X.A, X.B, X.GroupName 
FROM TableA X 
INNER JOIN TableB Y WITH (INDEX(ClusteredIndexName)) -- Huge table 
ON (X.A = Y.Name OR X.B = Y.Name) 

你可以看到正在使用什麼指標通過在查詢菜單(CTRL + L,而不是CTRL使用「顯示估計的執行計劃」 + E),但很少實際的查詢將被調整不同。

我也推薦NOLOCK提示。普通查詢對他們訪問的數據設置共享鎖,防止更新這些行。這個鎖也有一些相關的開銷。使用NOLOCK可以加快查詢速度並提高併發性,但會導致髒讀。假設您的大型查詢中的其中一行在運行中更新。您可能會在結果中同時獲得新舊行(我認爲,從未見過它發生過)。如果您不使用NOLOCK,那麼該更新可能會阻塞,直到查詢完成,可能導致重要更新超時。

SELECT X.A, X.B, X.GroupName 
FROM TableA X WITH (NOLOCK) 
INNER JOIN TableB Y WITH (NOLOCK, INDEX(ClusteredIndexName)) -- Huge table 
ON (X.A = Y.Name OR X.B = Y.Name)