SQL Server 为什么不使用索引

标签 sql sql-server indexing

我在 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-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 行中的每一行,都需要一个 键查找到聚簇索引中以获取该数据 - 键查找是昂贵操作!所以最后,立即扫描集群索引可能会更容易、更高效。

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

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 不断推荐已经存在的索引......不要在这些上投入太多资金索引提示!

关于SQL Server 为什么不使用索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8342402/

相关文章:

sql - 转换非标mm :ss to hh:mm:ss with T-SQL

sql - 如何在设计过程中更改SQL表默认数据类型

Groovy GPars,启动的每个线程都需要索引

sql - 检查 CASE 语句中的空日期,我哪里出错了?

mysql - 用于选择传递日期时间的 SQL 子句语句 Codeigniter 事件记录

php - 使用 group by 子句对两列数据进行分组

sql - 无法写入属性 IsFileStream

MySQL 索引 |与 LIKE 一起使用

arrays - Swift - 如果包含字符串并附加到另一个数组,则在数组中搜索

mysql - 从其他表中选择列但应返回多行