复合列上的非CLustered Index引用

时间:2015-02-16 12:55:10

标签: sql-server tsql datetime optimization non-clustered-index

我在SQL Server中的datetime列(AdmitDate)和varchar列(Status)上有非聚集索引。现在的问题是,我只是根据datetime列(仅AdmitDate列上没有索引)过滤结果。

为了让我使用非聚集索引,我对varchar列(Status)使用了非空条件,但在该场景中,执行计划显示了"索引扫描&# 34。

select ClientName, ID 
from PatientVisit  
where 
    (PatientVisit.AdmitDate between '2010-01-01 00:00:00.000' AND '2014-01-31 00:00:00.000' ) 
    AND PatientVisit.Status is not null

-- Index Scan

但是如果我传递一个特定的状态值,那么按预期执行计划会显示Index Seek。

select ClientName, ID 
from PatientVisit  
where 
    (PatientVisit.AdmitDate between '2010-01-01 00:00:00.000' AND '2014-01-31 00:00:00.000') 
    AND PatientVisit.Status = 'ADM'

--Index Seek

我应该在运算符中使用并传递Status列的所有可能值以使用非聚集索引吗?

或者还有其他方法可以使用索引吗?

谢谢,

Shubham

2 个答案:

答案 0 :(得分:1)

您正在使用SELECT ClientID, Name并且您获取不属于索引的列,SQL Server将需要转到实际数据页以获取这些列值。

因此,如果SQL Server在非聚集索引中找到匹配项,则必须对聚簇索引执行(昂贵的)键查找以获取包含所有列的数据页。

如果有太多行Status为NULL,SQL Server会得出这样的结论:它只是对整个索引的血腥扫描更快,而不是做了很多索引寻找和关键查找。在另一种情况下,当您定义特定值并且仅匹配少数(或仅一个)行时,实际执行索引查找和一个昂贵的键查找可能会更快。 / p>

可以尝试的事情是使用包含SELECT所需的那两列的索引:

CREATE NONCLUSTERED INDEX IX_PatientVisit_DateStatusIncluded
ON dbo.PatientVisit(AdmitDate, Status)
INCLUDE(ClientID, Name)

现在在这种情况下,SQL Server可以在索引页面页面中找到满足此查询所需的值,因此实际上使用那个索引 - 即使它发现很多点击 - 可能在那个小索引上有一个索引扫描(这也不错!)

答案 1 :(得分:0)

创建filtered index。然后,您可以仅为status为非null的值创建datetime字段的索引。

CREATE NONCLUSTERED INDEX FI_IX_AdmitDate_StatusNotNull
  ON dbo.PatientVisit(AdmitDate)
  WHERE Status IS NOT NULL

这将用于您的查询Status IS NOT NULL,您的现有索引将用于Status = 'ASpecificValue'

的查询