Sql server 为什么不是';优化器是否使用我的唯一筛选索引?

Sql server 为什么不是';优化器是否使用我的唯一筛选索引?,sql-server,Sql Server,示例架构: 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, Encrypted

示例架构:

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是集群的关键(最终的计划也证明了这一点,但这不是问题的重点)


然而,优化器选择在IX_Person_登录上执行索引搜索,它不是唯一的,在键中有更多的列,并且其叶节点更大。如果我强制使用IX_Person_用户名,估计成本是相同的。在这两种情况下,估计行数都超过100,但实际行数为1。我尝试更新统计数据,但这对所选计划或估计行数也没有任何影响。是否因为SQL Server的计划考虑了@UserName可能为null的可能性?即使我在查询中放入一个文本非空字符串值,它仍然不使用唯一的筛选索引。有人能解释这种行为吗?

查询优化者不一定选择最佳计划

这是有道理的,因为有时候最好是按照你现在的好计划来执行,而不是浪费很多时间去寻找一个更快的计划

如果要强制查询使用该索引,则可以使用表提示

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_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%

尝试将ID包含在index@mxix没有必要,因为它是群集的index@Lamak,他想要一个给定的身份证。由于IX_Person_用户名不包含ID,因此不会使用它。如果IX_Person_Username包含ID,优化器可能会为给定查询选择该ID。@mxix每个非聚集索引都包含聚集索引的键(如果表中有)。因此,是的,
X_Person\u用户名
确实包含
ID
@Lamak是正确的。当我强制使用带有表提示的IX_Person_用户名时,查询计划是对索引的简单索引搜索。如果索引没有覆盖查询,那么也会有书签查找。感谢您的提醒,有时候优化器会选择“足够好”而不是“由我决定最好”
Query1: Query cost (relative to the batch): 50%

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