将聚簇索引扫描优化为聚簇索引查找

Posted

技术标签:

【中文标题】将聚簇索引扫描优化为聚簇索引查找【英文标题】:Optimize the Clustered Index Scan into Clustered Index Seek 【发布时间】:2018-10-15 11:54:35 【问题描述】:

有一个场景,我有 40 列的表,我必须选择一个表的所有数据(包括所有列)。我在表上创建了一个聚集索引,它包括聚集索引扫描,同时从表中获取完整的数据集。

我知道,如果没有任何过滤器或连接键,SQL Server 将选择 Clustered Index Scan 而不是 Clustered Index Seek。但是,我想通过将 Clustered Index Scan 优化为 Clustered Index Seek 来优化执行计划。有什么解决方案可以实现这一目标吗?请分享。

下面是执行计划的截图:

【问题讨论】:

为什么?它会像垃圾一样运行。 【参考方案1】:

问题/请求中的某些内容不太正确,因为您所要求的内容将表现不佳。我怀疑这是因为误解了什么是聚集索引。

聚集索引——也许更好地表述为聚集表——是数据表,它不与表分离,它表。如果表上数据的顺序已经基于 ITEM ID,那么扫描是查询的最有效访问方法(尤其是考虑到select *)——你根本不想在这种情况下寻找——而且我由于排序运算符,请不要相信这是您的情况。

如果聚集表是基于另一个字段排序的,那么您将需要一个额外的非聚集索引来提供正确的顺序。然后,您将尝试强制执行一个非聚集索引扫描、嵌套循环到聚集索引查找的计划。这可以使用查询提示来实现,INNER LOOP JOIN 很可能会导致搜索 - 但也存在可以使用的 FORCESEEK

就性能而言,第二个选项永远不会赢 - 实际上你正在寻找一个临界点概念 (https://www.sqlskills.com/blogs/kimberly/the-tipping-point-query-answers/)

【讨论】:

【参考方案2】:

好吧,我也想达到同样的效果,我希望在我的***查询上进行索引搜索而不是索引扫描。

SELECT TOP 5 id FROM mytable

这是查询的执行计划:

我什至尝试了Offset Fetch Next的方法,计划是一样的。

为了避免索引扫描,我加入了一个假主键过滤器,如下所示:

SELECT TOP 5 id FROM mytable where id != 0

我知道,我的主键中不会有 0 值,所以我在顶部查询中添加了它,这被解析为索引查找而不是索引扫描:

尽管如此,查询计划比较给出了与其他类似的操作成本,对于这方面的索引查找和扫描。但我认为以这种方式实现索引搜索,这是db执行的额外操作,因为它必须比较id是否为0。如果我们想要前几条记录,我们完全不需要它。

【讨论】:

以上是关于将聚簇索引扫描优化为聚簇索引查找的主要内容,如果未能解决你的问题,请参考以下文章

聚簇索引和非聚簇索引

聚簇索引与非聚簇索引(也叫二级索引)

MySQL调优索引优化

数据库中聚簇索引与非聚簇索引的区别 (整理)

Oracle索引聚簇因子的含义及重要性

索引结构(BTreeB+Tree和Hash等)和分类(聚簇索引与非聚簇索引等)