我在SQL Server 2008数据库中有一个下表:
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
)
有20 000行执行日期等于'2500-01-01'和420 000行已执行日期< '2500年1月1日'。
执行查询时
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%的数据,为什么不使用索引?
答案 0 :(得分:4)
最有可能的情况是,查询优化器只会看到您正在选择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连续推荐已经存在的索引.....不要在这些上下注太多钱索引提示!