SQL Server 为啥不使用索引
Posted
技术标签:
【中文标题】SQL Server 为啥不使用索引【英文标题】:SQL Server why index is not usedSQL Server 为什么不使用索引 【发布时间】:2011-12-01 13:50:39 【问题描述】:我在 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
)
执行日期等于“2500-01-01”的 20 000 行和执行日期
当我执行查询时
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% 的数据,为什么不使用索引?
【问题讨论】:
【参考方案1】:最有可能的是,查询优化器只看到您也在选择 DisplayText
- 因此对于在 NC 索引中找到的 20'000 行中的每一行,都需要进行 键查找 进入聚集索引以获取该数据 - 键查找是 昂贵 操作!因此,最终,立即扫描集群索引可能更容易、更有效。
我敢打赌,如果你在这里运行这个查询:
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 不断推荐已经存在的索引.....不要在这些上押太多钱索引提示!
【讨论】:
是的,您对 DisplayText 的看法是正确的。您说 20000 键查找比扫描整个聚集索引更昂贵?好的,谢谢你的信息。 @WaldiMen:测试一下! :-) 您可以通过WITH (INDEX(IX_Actions_Executed))
强制 SQL Server 使用索引 - 比较执行计划、执行时间和 I/O 统计信息。另外:尝试 covering index 方法 - 如果包含 DisplayText
列,我很确定它会被使用....以上是关于SQL Server 为啥不使用索引的主要内容,如果未能解决你的问题,请参考以下文章
为啥当 WHERE 子句包含参数化值时 SQL Server 使用索引扫描而不是索引查找