繁体   English   中英

为什么SQL Server使用索引扫描而不是Seek + RID查找?

[英]Why does SQL Server use an Index Scan instead of a Seek + RID lookup?

我有一张桌子。 1.35亿行:

CREATE TABLE [LargeTable]
(
    [ID] UNIQUEIDENTIFIER NOT NULL,
    [ChildID] UNIQUEIDENTIFIER NOT NULL,
    [ChildType] INT NOT NULL
)

它具有不包含列的非聚集索引:

CREATE NONCLUSTERED INDEX [LargeTable_ChildID_IX]
  ON [LargeTable] 
(
    [ChildID] ASC
)

(它聚集在ID )。

我希望将其加入一个包含几千行的临时表中:

CREATE TABLE #temp
(
    ChildID         UNIQUEIDENTIFIER PRIMARY KEY,
    ChildType       INT
)

...add #temp data...

SELECT lt.ChildID, lt.ChildType
    FROM #temp t
    INNER  JOIN [LargeTable] lt
        ON lt.[ChildID] = t.[ChildID]

但是查询计划包括对大表的索引扫描:

索引扫描

如果我更改索引以包括额外的列:

CREATE NONCLUSTERED INDEX [LargeTable_ChildID_IX] ON [LargeTable] 
(
    [ChildID] ASC
)
INCLUDE [ChildType]

然后,查询计划更改为更明智的方法:

索引搜寻

所以我的问题是:为什么在第一种情况下,SQL Server仍然不能使用索引查找,而是使用RID查找从非聚集索引获取表数据? 肯定会比在如此大的表上进行索引扫描更有效吗?

实际上,第一个查询计划很有意义。 请记住,SQL Server从不读取记录,而是读取页面。 在您的表中,一个页面包含许多记录,因为这些记录非常小。

对于原始索引,如果要使用第二个查询计划,则在找到索引中的所有RID并读取索引页以执行此操作之后,需要读取聚集索引中的页以读取ChildType列。 在最坏的情况下,它需要读取每个记录的整个页面。 由于每页有很多记录,因此可能归结为读取聚集索引中很大比例的页面。

SQL Server根据统计数据猜测,仅扫描聚集索引中的页面将总共需要较少的页面读取,因为这样可以避免读取非聚集索引中的页面。

这里重要的是临时表中的数与大型表中的页数相比。 假设ChildID在大型表中的分布是随机的,则临时表中的行数接近或取代大型表中的页数时,SQL Server仍将不得不读取大型表中的几乎每个页面。

由于索引中未包含ChildType列,因此必须返回到聚集索引(具有提到的Row IDentifier查找)才能获取ChildType的值。
当您将此列INCLUDE在非聚集索引中时,它将被添加到索引的叶级,在该叶级可以进行查询。

俗称“索引临界点” 基本上,基于成本的优化器在什么时候认为进行扫描比查找+查找更有效。 通常大约是大小的20%,在您的情况下,该大小将基于#temp表统计信息得出的估算值。 因人而异。

您已经有了答案:包括必填列,进行索引覆盖。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM