0

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

为了让我利用非聚集索引,我对varchar列 ( Status) 使用了非空条件,但在这种情况下,执行计划显示“索引扫描”。

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

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

或者有没有其他方法可以利用索引?

谢谢,

舒巴姆

4

2 回答 2

1

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

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

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

可以尝试的方法是使用一个索引,其中包含您需要的两列SELECT

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

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

于 2015-02-16T13:10:26.197 回答
0

创建过滤索引。然后,您可以仅为状态不为空的值创建日期时间字段的索引。

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

这将用于您的查询 whereStatus IS NOT NULL并且您现有的索引将用于查询 whereStatus = 'ASpecificValue'

于 2015-02-16T13:01:30.290 回答