我有一个名为tbl_event
的数据库表,其中非聚集索引IDX_Event_Folder
和IDX_Event_Time
定义为:
CREATE NONCLUSTERED INDEX [IDX_Event_Folder]
ON [dbo].[tbl_event]([nobjectid] ASC)
CREATE NONCLUSTERED INDEX [IDX_Event_Time]
ON [dbo].[tbl_event]([tetime] ASC)
我运行了以下简单查询,并直接在下面显示了执行计划:
查询1:
SELECT *
FROM tbl_event
WHERE tbl_event.nobjectid = 1410000
ORDER BY tetime
查询2:
SELECT *
FROM tbl_event
WHERE tbl_event.nobjectid = 1410000
我的问题是,为什么 nobjectid 的索引从未被使用过?我希望在这些select语句的where子句中指定nobjectid时会有索引搜索或扫描。我对这种分析的理解不正确吗?
答案 0 :(得分:3)
为什么nobjectid上的索引永远不会 利用?我希望有 当nobjectid时索引搜索或扫描 在where子句
中指定
一种常见的误解!
有一点是:因为您正在使用SELECT *
,所以您需要表格中的所有数据。所以最后,SQL Server必须返回实际的数据页并获取所有值。
当索引搜索发生并找到命中时,在这种情况下,SQL Server必须进行书签查找 - 这是一项相当昂贵的操作。
由于这些操作相当昂贵,SQL Server会尽量避免使用它们 - 因此在很多情况下,将使用表扫描,因为最终,这比寻找nc索引然后更快书签查找。
要检查的要点:
选择性如何成为nobjectid
列?这个听起来像一个或多或少独特的ID - 这将是好的。如果碰巧列上的索引不是很有选择性,那么查询优化器通常会忽略它(因为它必须检查太多行,所以最后表扫描更快)
表中有多少行?对于小表(少于几千行),从go go开始进行表扫描通常要快得多
另外,从你的第一个带有“RID堆查找”的执行计划,我得出结论,你没有桌面上的聚集索引 - 立即添加一个 !!没有聚簇键(因此具有堆而不是聚簇表)也会减慢大量操作并降低非聚集索引的有效性。
尝试在“NUSE”列上添加聚集索引:
INT IDENTITY
是一个完美的候选人 - UNIQUEIDENTIFIER
或非常宽的复合列是最差的。阅读有关在Kimberly Tripp's blog
答案 1 :(得分:2)
你在评论中说,目前表中有18325170行,其中只有约30个有nobjectid = 1410000。
即使您的IDX_Event_Folder
索引已被禁用,我也无法相信SQL Server会为该行数量选择此计划,并且行厚度表明它认为它正在处理可能是1行而不是18325170!
所以我很确定您必须禁用自动更新统计信息?如果是这样,您将需要手动更新统计信息(或最好启用此选项)
答案 2 :(得分:1)
有几个重叠的事情正在进行中
SELECT *
表示“给我所有专栏”。优化器决定扫描表格更有用。SELECT *
结合使用时使用索引?如果你有这个,那么将使用索引(作为扫描)
SELECT nobjectid
FROM tbl_event
WHERE tbl_event.nobjectid = 1410000
或者说,新索引最有可能被使用
CREATE NONCLUSTERED INDEX [IDX_Co,bined]
ON [dbo].[tbl_event]([nobjectid] ASC, tetime)
SELECT nobjectid, tetime
FROM tbl_event
WHERE tbl_nobjectid = 1410000
ORDER BY tetime
我建议你阅读这些文章
这些文章也应该涵盖聚集索引的缺失