2013-07-25 37 views
12

在我們的數據庫中,我們有這樣的表200.000行爲什麼SQL Server不使用我的索引?

CREATE TABLE dbo.UserTask (
    UserTask_ID int NOT NULL IDENTITY (1, 1), 
    UserTask_SequenceNumber int NOT NULL DEFAULT 0, 
    UserTask_IdEntitat uniqueidentifier NOT NULL, 
    UserTask_Subject varchar(100) NOT NULL, 
    UserTask_Description varchar(500) NOT NULL, 
      ..... 
      ..... 
    CONSTRAINT [PK_UserTask] PRIMARY KEY CLUSTERED 
    (
     [UserTask_ID] ASC 
    ) ON [PRIMARY] 
) ON [PRIMARY] 

我創建了一個索引上UserTask_IdEntitat

CREATE NONCLUSTERED INDEX IX_UserTask_IDEntitat ON dbo.UserTask 
(
    UserTask_IDEntitat 
) 

執行下面的查詢執行計劃顯示我們UserTask_IDEntitat該指數用於要做的查詢:

SELECT UserTask_ID 
    FROM UserTask 
WHERE UserTask_IdEntitat = @IdEntitat 
ORDER BY UserTask_LastSendSystemDateTime desc 

但是,如果我們在添加另一列列表,那麼不使用索引

SELECT UserTask_ID, UserTask_SequenceNumber, UserTask_IDEntitat, ....., UserTask_Subject 
    FROM UserTask 
WHERE UserTask_IdEntitat = @IdEntitat 
ORDER BY UserTask_LastSendSystemDateTime desc 

爲什麼從添加主鍵不同的列,使該SQL Server的執行計劃不使用索引的列UserTask_IDEntitat

在此鏈接http://bytes.com/topic/sql-server/answers/144592-sqlsever-not-using-index之後,它似乎是過濾值在列上重複的次數,它可以使索引不被使用,但我嘗試使用重複的@IeEntitat值執行查詢60.000次等僅重複175次,結果相同,IDEntitat列的索引被忽略。

這讓我瘋狂!

感謝您的幫助。

+3

如果你是在一個合適的版本,這是一個常見的查詢,你可能想看看'INCLUDE索引中的'_SequenceNumber'。 –

+0

......還有'LastSendSystemDateTime',我想。 (爲了幫助'按'排序)。 –

回答

32

確定 - 只要您僅選擇索引中的列或來自集羣鍵(通常是主鍵)的列,那麼索引將是因爲SQL Server可以在索引導航結構的葉級找到它需要的所有信息(UserTask_IDEntitat列和聚簇索引列)。因此,它可以直接從索引的葉級頁面返回查詢所需的數據。

但是:如果您需要選擇第二列,即既不在索引定義也聚集鍵的一部分,那麼SQL服務器將不得不做一個所謂的書籤查找轉化爲實際的數據頁面。

所以爲每一個排它在你的非聚集索引查找,那就要採取聚類索引值,搜索聚集索引查找在這個聚集索引的葉級的實際數據頁,然後挑出你想要的那一列。

書籤查找適用於少量點擊 - 如果您選擇數千行,它們對性能完全具有破壞性。在這種情況下,SQL Server查詢優化器正確使用聚簇索引掃描代替 - 因爲在聚簇索引中,在葉級別上,它有所有行立即可用。

所以:如果您在UserTask_IDEntitat有一個索引,你有時需要第二列UserTask_SequenceNumber太 - 那麼你可以包括,在你那非聚集索引列:

CREATE NONCLUSTERED INDEX IX_UserTask_IDEntitat 
ON dbo.UserTask(UserTask_IDEntitat) 
INCLUDE(UserTask_SequenceNumber) 

有了這個,額外的列僅出現在非聚集索引的葉級中(它不能在WHERE子句中使用 - 它不是索引的導航結構的一部分!) - 並且您的第二個SELECT可以再次從葉子非聚集索引的級別節點 - > no ex需要沉思書籤查找 - >您的索引將再次使用。

長話短說:除非你非聚集索引是高度選擇性(如返回的行或1%以下),除非你非聚集索引是覆蓋指數(包含所有的索引這些列需要滿足特定的查詢),那麼SQL Server將會使用非聚簇索引NOT進行的更改非常高。

欲瞭解更多信息

+0

感謝您的詳細答案和您的有用鏈接,我真正需要的生產查詢不僅返回UserTask_SequenceNumber,我需要返回所有列(第二個查詢是一個不好的例子),在這種情況下,不存在任何緩和的optimitzation要做,不是? SqlServer正在做最有效的方式是可能的。 –

+2

@MarcCals:如果你需要**所有**列 - 那麼大多數時候索引並不會真的有幫助,因爲執行聚集索引掃描通常比做數千個昂貴的書籤查找更有效 –