我在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
答案 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'