SQL Server 2008R2 - 为什么我的索引没有被使用

jim*_*imw 5 index null hints sql-server-2008-r2

我有一个按以下方式定义的表:

CREATE TABLE [dbo].[MyTable]
(
   [MyTable_ID] [int] IDENTITY(1,1) NOT NULL,
   [COLUMN_WITH_DATA] [varchar](128) NOT NULL,
   [COLUMN_A] [varchar](128) NULL,
   [COLUMN_B] [varchar](128) NULL,
   [COLUMN_C] [bit] NOT NULL
)
Run Code Online (Sandbox Code Playgroud)

和这样创建的索引:

CREATE INDEX [MyTable_Index_ABC] ON [dbo].[MyTable]
(
    [COLUMN_A],
    [COLUMN_B], 
    [COLUMN_C]
) 
ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

我运行以下查询:

SELECT TOP 1 [MyTable].*
    FROM [MyTable](UPDLOCK)
    WHERE
        [MyTable].[COLUMN_A] IS NULL
    AND [MyTable].[COLUMN_B] IS NULL
    AND [MyTable].[COLUMN_C] = 0
Run Code Online (Sandbox Code Playgroud)

这背后的目标是获取第一个尚未使用的记录的 COLUMN_WITH_DATA 值,然后使用非空值更新其 COLUMN_A 和 COLUMN_B,以将其标记为已使用。

我在 MyTable 中有几百万条记录,其中大约一半都有:COULMN_A 和 COLIMN_B 不是 NULL(表明数据已经被消耗)。

在这种情况下,查询运行非常缓慢,执行计划显示索引:

MyTable_Index_ABC
Run Code Online (Sandbox Code Playgroud)

除非我使用查询提示,否则不使用,在这种情况下查询运行得更快。另一方面,如果我更新所有尚未消耗的行,那就是:

COLUMN_A IS NULL AND COLUMN_B IS NULL
Run Code Online (Sandbox Code Playgroud)

以便 COLUMN_A 和 COLUMN_B 包含空字符串:'' 而不是 NULL,使用索引并且查询再次运行得更快。

两个问题是:

  1. 为什么空值使我的索引被丢弃
  2. 是否可以指示数据库始终使用索引而不必对可能的多个不同查询使用查询提示?

谢谢,

Sna*_*Jag 6

我喜欢直接回答问题;然而,这个话题可以更深入更长时间,因此我在底部添加了几篇文章,扩展了这些细节,供所有人学习。

总之 ...

一些可能影响使用索引的事情(请注意,还有很多原因,您将在下面发布的文章中看到)。引擎的主要优先级是预测如何以最有效/最高效的方式(使用统计数据)尽快从磁盘中获取数据。引擎的主要选择是执行表扫描或索引查找/扫描。(本次对话可以有更深入的内容,但我会将其保留在您问题的上下文中)。

  1. 在 SELECT 中使用较少的字段,这些字段与 INDEX KEY 和 INDEX INCLUDES 更具凝聚力。
  2. 表中的更多行将与索引的使用相关联
  3. 行的选择性(唯一性)越多,使用索引的可能性就越大,因此很多 NULL 值会导致引擎避开索引

详细 ...

使用表扫描或索引扫描/查找的原因是什么。这些也是在大多数一般情况下确定索引创建和使用的一般帮助程序。遵循以下几个步骤,您将从一开始就获得巨大的收益。

其中一个原因,因为它是在上述意见中提到,是从哪儿使用SELECT *的。SELECT * 是引擎决定避免使用索引的可靠方式。通过从表本身扫描/检索,绕过任何索引,从表(聚集索引/堆)中获取所有字段会更快。第一个人工选择是将您的选择字段最小化为 INDEX KEY 和 INDEX INCLUDES 中的字段。

第二个原因是多少条记录在表中。记录越少,引擎就越容易简单地扫描表。统计数据可以参与其中。因为引擎会使用统计信息来预测数据在页面/磁盘上的位置,所以可以说没有足够的行/分布来使用索引。

第三,具有较小的选择性(较少独特)在表中的值,如男性和女性,就越有可能的指数将被使用。在查询中更多使用索引的表将用于高度选择性(更独特)的字段,例如地址表中的邮政编码(只要您的地址列表不是所有具有相同邮政编码的邻居)。

有许多技术和策略。但有一条建议,在阅读和体验索引/统计数据以及如何/将它们放在磁盘/LUNS 上的位置方面变得知识渊博,您将成为一名 DBA 并提供巨大的性能提升。