SQL服务器,为什么不使用索引

问题描述:

我在SQL Server中的表2008数据库:SQL服务器,为什么不使用索引

CREATE TABLE [dbo].[Actions](
    [ActionId] [int] IDENTITY(1,1) NOT NULL,  
    [ActionTypeId] [int] NOT NULL, 
    [Name] [nvarchar](50) NOT NULL, 
    [Description] [nvarchar](1000) NOT NULL, 
    [Comment] [nvarchar](500) NOT NULL, 
    [Created] [datetime] NOT NULL, 
    [Executed] [datetime] NULL, 
    [DisplayText] [nvarchar](1000) NULL,  
    [ExecutedBy] [int] NULL, 
    [Result] [int] NULL 
) 
CONSTRAINT [PK_Actions] PRIMARY KEY CLUSTERED 
(
    [CaseActionId] ASC 
) 
) ON [PRIMARY] 

GO 


CREATE NONCLUSTERED INDEX [IX_Actions_Executed] ON [dbo].[Actions] 
(
    [Executed] ASC, 
    [ExecutedBy] ASC 
) 

有已经执行日期等于“2500年1月1日”和420 000列20行000已执行日期<'2500-01-01'。

当我执行一个查询

select CaseActionId, Executed, ExecutedBy, DisplayText from CaseActions 
where Executed='2500-01-01' 

查询计划表明,在PK_Actions聚集索引执行扫描和索引IX_Actions_Executed完全不使用。

我有什么有趣的缺失索引提示它说

/* The Query Processor estimates that implementing the following index could improve the query cost by 99.9901%. 
*/ 

CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>] 
ON [dbo].[Actions] ([Executed]) 

不过该指标已经存在。

为什么索引不被使用,如果它会选择5%的数据?

最有可能的,查询优化器只是看到您要选择DisplayText以及 - 因此每个在NC指数发现20'000行的,就需要一个键查找到聚集索引获取该数据 - 并且键查找昂贵的操作!因此,最终,立即扫描clustere索引可能会更容易,更高效。

我敢打赌,如果你在这里运行此查询:

select CaseActionId, Executed, ExecutedBy 
from CaseActions 
where Executed='2500-01-01' 

那么NC指数将用于

如果你真的需要DisplayText,这就是你经常运行的查询,也许你应该包括在索引列在叶级别一个额外的列:

DROP INDEX [IX_Actions_Executed] 

CREATE NONCLUSTERED INDEX [IX_Actions_Executed] 
ON [dbo].[Actions]([Executed] ASC, [ExecutedBy] ASC) 
INCLUDE([DisplayText]) 

这将使您的NC指数覆盖指数,即它可以返回查询所需的所有列。如果你再次使用这个覆盖索引来运行你的原始查询,我很肯定SQL Server的查询优化器确实会使用它。如果NC指数是覆盖指数,例如,将使用任何NC指数的概率为,则显着增加。有些查询可以从NC索引中获得他们所需的所有列,而无需查找关键字。

缺少的索引提示有时会有点误导 - 还有一些已知的错误可导致SQL Server Mgmt Studio不断推荐已经存在的索引.....不要将太多的钱投入到这些索引提示!

+0

是的,你是正确的显示文本。你说20000键查找比整个聚簇索引的扫描要贵?好的,谢谢你的信息。 – WaldiMen

+0

@WaldiMen:测试它! :-)你可以强制SQL Server通过'WITH(INDEX(IX_Actions_Executed))'来使用索引 - 比较执行计划,执行时间和I/O统计。另外:尝试**覆盖索引**的方法 - 我敢肯定,如果包含“DisplayText”列,它将被使用.... –