2009-06-05 614 views
3

我有一件奇怪的事情正在進行查詢。我有兩張bigint的表,StartNum和EndNum定義了數字範圍。我有這兩列的索引。查詢需要一個給定的數字並返回它所在的範圍。 WHERE子句是where @Num >= StartNum and @Num <= EndNumSQL索引搜索

Profiler在搜索列表開頭附近的數字和結束附近的數字之間有很大區別。數字越大,讀取和持續時間就越多。查詢計劃顯示它在我的索引上使用查找。

作爲一個索引是一棵平衡樹,肯定不應該有太大的差異。有人可以向我解釋這個嗎?

小字樣: 這是SQL 2005 Workgoup版本。表中約有20萬行。該索引是非聚簇(聚簇索引位於標識列上,但數據已按StartNum順序插入)。該指數有716頁,深度爲3,分數爲3%。

+0

StartNum或EndNum上的索引?該計劃正在做一個尋求或尋求,然後掃描(它聽起來是這樣)。你爲什麼期望一列中的一個索引能夠滿足*兩個條件? – 2009-06-05 16:33:47

+0

嗨Remus, 該索引位於兩列,只有索引查找。 – 2009-06-08 06:52:28

回答

0

破解它!

EndNum始終> = StartNum,所以我只需要找到最大的StartNum即< = @Num。我將索引更改爲StartNum desc並將查詢更改爲top 1 ... where StartNum <= @Num order by StartNum desc。現在對於任何@Num的值來說,它只是一個索引查找,有5個讀取和0個持續時間,這正是我之後的情況。

感謝您的幫助,夥計們。

1

這取決於您的查詢。如果你只查詢這兩個值,例如:

SELECT StartNum, EndNum 
FROM Books 
WHERE (@Num >= StartNum) AND (@Num <= EndNum) 

在這種情況下,SQL Server只具有通過兩個指標來尋求回報的數字。你的兩個索引包含你被編入索引的值,因爲它是一個索引。

但我敢肯定,你實際上包括查詢等欄目:

SELECT BookID, Title, IDBN, Author, StartNum, EndNum 
FROM Books 
WHERE (@Num >= StartNum) AND (@Num <= EndNum) 

在這種情況下,SQL Server中,一旦發現ID「匹配的行第標準,必須再回去到數據庫中,找到那些行,以便它可以返回你:

  • 標題
  • ISBN
  • 作者

除了已經擁有的值從兩個指標:

  • StartNum
  • EndNum
  • BOOKID

注:的上StartNum指數含蓄地包含聚集鍵的值,因爲這就是它知道哪一行對應於條目i的情況指數。

問題是,如果「書太多」,它必須在表中查找,那麼讀取整個表格可能會更快。


打個比方:你看書的索引中所有對「設計模式」的引用。

設計模式:4,89,221,442

如果只有4項,那麼你會不會介意的向後翻轉到索引中列出的頁面。這被稱爲書籤查找

但是如果索引表示有827條引用一個短語會怎麼樣?

電腦:1,2,6,[剪斷825項] 1087及1128

那麼它可能只是更快的通過閱讀本書自己找到它們。在這種情況下,我們放棄並掃描整本書。 SQL Server調用此聚集一索引掃描,如果表中有聚簇索引,或者表掃描如果沒有聚集索引(即它是一個「堆表」)


如果你是隻需在您的查詢中提供StartNumEndNum(假設您正在計數),那麼我相信您會看到一貫的低讀取和執行時間。但是,如果包含其他列,並且SQL Server認爲該查詢返回的行數太多(例如,超過表的5%),那麼它只會忘記索引並掃描整個表。

有一個交叉點,在SQL Server知道StartNum,並在表中EndNum值的分佈,因爲它的樣本值,並且對它們的分佈統計。如果@Num的某些值會返回幾行,並且SQL Server知道這一點,則它將執行相對較少的書籤查找。但是,如果您的數據分佈會導致更多行返回,那麼您將獲得聚簇索引掃描

+0

謝謝,伊恩,但它確實如我所說的那麼簡單。我從更多的角度開始,所以我將其全部剝離,直到從索引中選擇列。沒有書籤查找或其他任何東西。只是索引尋找我的索引。取決於所尋找的數字下降的「列表」有多遠,閱讀和持續時間仍然存在很大差異。 – 2009-06-05 15:33:37

0

您是否在StartNum ASC,EndNum DESC上編入索引?

因爲如果您在StartNum ASC,EndNum ASC上編入索引,我預計它無法執行兩個搜索。它必須進行尋找和掃描。

另一種可能性是分別在StartNum和EndNum上進行索引(順序無關緊要),看看它是否會按順序使用兩個索引,然後進行某種連接。

直到你看到不同的執行計劃時,你才能真正知道。

我無法複製沒有真正列的行爲。我建立了一個包含200000個StartNum-EndNum範圍100-199,200-299等的測試表。我已經能夠讓它做一個聚簇索引掃描,表掃描和一個非聚簇索引查找,但沒有任何東西接近你在說什麼。