SQL Server非聚集索引永远不会出现在执行计划中

发布于 2024-10-16 23:08:50 字数 855 浏览 4 评论 0原文

我有一个名为 tbl_event 的数据库表,其非聚集索引 IDX_Event_FolderIDX_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

查询 1 的执行计划

查询 2:

SELECT * 
FROM tbl_event 
WHERE tbl_event.nobjectid = 1410000

查询2的执行计划

我的问题是,为什么索引在nobjectid上从未使用过?我希望当这些 select 语句的 where 子句中指定 nobjectid 时,会有索引查找或扫描。我对这个分析的理解是否错误?

I have a database table called tbl_event with the non-clustered indexes IDX_Event_Folder and IDX_Event_Time defined as:

CREATE NONCLUSTERED INDEX [IDX_Event_Folder] 
ON [dbo].[tbl_event]([nobjectid] ASC)

CREATE NONCLUSTERED INDEX [IDX_Event_Time] 
ON [dbo].[tbl_event]([tetime] ASC)

I ran the following simple queries and got the execution plans displayed directly underneath:

Query 1:

SELECT * 
FROM tbl_event 
WHERE tbl_event.nobjectid = 1410000
ORDER BY tetime

Execution Plan for Query 1

Query 2:

SELECT * 
FROM tbl_event 
WHERE tbl_event.nobjectid = 1410000

Execution Plan for Query 2

My question is, why is the index on nobjectid never utilized? I would expect there to be an index seek or scan when nobjectid is specified in the where clause of these select statements. Is my understanding of this analysis incorrect?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

倒带 2024-10-23 23:08:50

为什么nobjectid上的索引从来没有
利用?我希望有
当 nobjectid 时进行索引查找或扫描
在where子句中指定

一个常见的误解!

一点是:由于您使用的是 SELECT *,因此您需要表中的所有数据。所以最后,SQL Server 必须返回到实际的数据页并获取所有值。

当发生索引查找并找到命中时,在这种情况下,SQL Server 必须执行书签查找 - 这是一个相当昂贵的操作。

由于这些操作相当昂贵,SQL Server 将尽可能避免它们 - 因此在许多情况下,将使用表扫描,因为最终,这比查找 nc 索引然后进行书签查找要快。

检查要点:

  • nobjectid 列的选择性如何?这里的这个听起来或多或少是一个唯一的 ID——那就太好了。如果您碰巧在选择性不强的列上有一个索引,那么查询优化器通常会忽略它(因为它必须检查太多行,所以表扫描最终会更快)

  • 表中有多少?对于小型表(少于几千行),从一开始就进行表扫描通常要快得多

此外,从您使用“RID堆查找”的第一个执行计划来看,我得出的结论是您没有集群表格上的索引 - 立即添加一个!没有聚集键(因此使用而不是聚集表)也会减慢大量操作并降低非聚集索引的有效性。

尝试在“NUSE”列上添加聚集索引:

  • 唯一
  • 稳定
  • 不断增加的

INT IDENTITY 是完美的候选者 - UNIQUEIDENTIFIER 或非常宽的复合列集是最佳选择最糟糕的。阅读有关选择正确聚集索引的所有信息,请访问 Kimberly特里普的博客

why is the index on nobjectid never
utilized? I would expect there to be
an index seek or scan when nobjectid
is specified in the where clause

A common misconception!

One point is: since you're using SELECT *, you want all data from the table. So in the end, SQL Server must go back to the actual data pages and fetch all the values.

When an index seek occurs and finds a hit, then in this case, SQL Server has to do a bookmark lookup - a rather expensive operation.

And since those operations are rather expensive, SQL Server will try to avoid them if it can - so in many cases, a table scan will be used instead, since in the end, that's faster than seeking the nc index and then doing a bookmark lookup.

Points to check:

  • how selective is the nobjectid column? This one here sounds like a more or less unique ID - that would be good. If you happen to have an index on a column that would be not very selective, then often, the query optimizer will ignore it (since it would have to check too many rows already, so a table scan is quicker in the end)

  • how many rows are there in the table?? For small tables (less than a few thousand rows), it's often much faster to do a table scan from the get go

Also, from your first execution plan with the "RID heap lookup", I would conclude you don't have a clustered index on the table - add one right away!! Not having a clustered key (thus having a heap instead of a clustered table) also slows down lots of operations and reduces the effectiveness of a non-clustered index.

Try to add your clustered index on a "NUSE" column:

  • narrow
  • unique
  • stable
  • ever increasing

INT IDENTITY is a perfect candidate - UNIQUEIDENTIFIER or a very wide compound set of columns are the worst. Read all about choosing the right clustered index at Kimberly Tripp's blog

我的鱼塘能养鲲 2024-10-23 23:08:50

您在评论中说表中当前有 18325170 行,其中只有大约 30 行的 nobjectid=1410000。

即使您的 IDX_Event_Folder 索引已禁用,我也无法相信 SQL Server 会为那么多行选择此计划,并且行粗细表明它认为它正在处理可能是 1 行而不是 18325170!

Plan

所以我很确定您必须禁用自动更新统计信息?如果是这样,您将需要手动更新统计信息(或者最好启用此选项)

You say in the comments that there are 18325170 rows currently in the table, only about 30 of them have nobjectid=1410000.

Even if your IDX_Event_Folder index was disabled I cannot believe that SQL Server would choose this plan for that amount of rows and the line thickness indicates it thinks it is dealing with maybe 1 row not 18325170!

Plan

So I'm pretty sure that you must have auto update statistics disabled? If so you will need to update the statistics manually (or preferably enable this option)

丑丑阿 2024-10-23 23:08:50

有几个重叠的事情发生

  • 您的 SELECT * 意思是“给我所有列”。优化器认为扫描表更有用。
  • 唯一有用的索引是用于排序的 tetime 索引。它执行此操作,然后钻取表。
  • 您没有聚集索引(RID/堆查找表明)
  • nobjectid 索引缺乏唯一性不会有帮助:这意味着完整索引扫描。 o 为什么在与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

我建议你阅读这些文章

这些文章也应该涵盖聚集索引的缺乏

There are several overlapping things going on

  • Your SELECT * means "give me all columns". The optimiser decides it's more useful to scan the table instead.
  • The only useful index is the tetime one for ordering. It does this, then drills into the table.
  • You have no clustered index (the RID/heap lookup shows that)
  • The lack of uniqueness on the nobjectid index won't help: it means an full index scan. o why use the index when combined with SELECT *?

If you had this, then the index will be used (as a scan)

SELECT nobjectid
FROM tbl_event 
WHERE tbl_event.nobjectid = 1410000

Or this, the new index would most likely be used

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

I suggest you read these articles

The lack of clustered index should be covered by these articles too

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文