2014-09-26 65 views
0

示例模式:爲什麼優化器不使用我獨特的過濾索引?

create table dbo.Person (
    ID int identity(1,1) not null 
     constraint PK_Person primary key, 
    UserName nvarchar(50) null, 
    EncryptedPassword nvarchar(100) null 
) 
create index IX_Person_Login 
    on dbo.Person (UserName, EncryptedPassword) 
    include (/* other columns */) 
create unique index IX_Person_UserName 
    on dbo.Person (UserName) 
    where (UserName is not null) 

所以,現在,如果我的用戶名做ID的查找,我希望的是更小,更選擇性指數將優化選擇。 IX_Person_UserName也應該被覆蓋,因爲ID是聚類關鍵(並且生成的計劃確實承擔了這一點,但這不是問題的關鍵)。

select ID 
from dbo.Person 
where UserName = @UserName 
and UserName is not null 

然而相反,優化選擇執行索引查找上IX_Person_Login,這不是唯一的,在關鍵的列多,並且其葉子節點大得多。如果我強制使用IX_Person_UserName,估計的成本是相同的。在這兩種情況下,估計的行數都超過了100,但實際的行數是1.我嘗試更新統計數據,但是在選擇的計劃或估計的行數方面沒有任何區別。是否因爲SQL Server的計劃考慮到@ UserName可能爲空的可能性?即使我在查詢中放置了一個字符串非空字符串值,它仍然不會使用唯一的已過濾索引。誰能解釋這種行爲?

+0

嘗試包括在索引中的ID – mxix 2014-09-26 16:39:02

+0

@mxix沒有必要,因爲它是聚簇索引 – Lamak 2014-09-26 16:44:47

+0

@Lamak,他想對給定的ID。由於IX_Person_Username不包含該ID,因此不會使用該ID。如果IX_Person_Username包含ID,優化器可能會爲給定的查詢選擇它。 – mxix 2014-09-26 16:51:48

回答

1

查詢優化器不一定選擇最佳計劃。

這很有道理,因爲它有時更好地運行在你現在擁有的好計劃上,而不是浪費很多時間尋找更快的計劃。

如果要強制查詢中使用該索引,然後你可以用表提示

SELECT Id FROM dbo.Person p 
WHERE UserName is not null 
OPTION (TABLE HINT(p , INDEX (IX_Person_UserName))) 

https://msdn.microsoft.com/en-us/library/ms181714.aspx

如果運行兩個版本,幷包括實際的執行計劃

SELECT Id FROM dbo.Person p 
WHERE UserName is not null 
OPTION (TABLE HINT(p , INDEX (IX_Person_UserName))) 

SELECT Id FROM dbo.Person p 
WHERE UserName is not null 
OPTION (TABLE HINT(p , INDEX (IX_Person_Login))) 

從相對於批處理的查詢成本中您可以看到它是否實際上有任何區別。

我想你會看到

Query1: Query cost (relative to the batch): 50% 

Query2: Query cost (relative to the batch): 50% 
+0

https://msdn.microsoft.com/en-us/library/ms181714.aspx – 2015-12-04 16:46:18

+0

感謝您的提醒,有時優化器會選擇「足夠好」,而不是「由我決定的最佳」 – 2015-12-08 23:49:46

相關問題