为什么NonClustered索引扫描比聚簇索引扫描更快?

时间:2014-11-28 17:58:51

标签: sql sql-server indexing sql-execution-plan full-table-scan

据我所知,堆表是没有聚簇索引的表,没有物理顺序。 我有一个堆栈表“扫描”,有120k行,我正在使用这个选择:

SELECT id FROM scan

如果我为列“id”创建非聚集索引,我会得到 223个物理读取。 如果我删除非聚集索引并更改表以使“id”成为我的主键(以及我的聚集索引),我会得到 515个物理读取

如果聚集索引表是这样的图片:

enter image description here

为什么Clustered Index Scans像表扫描一样工作? (或者在检索所有行的情况下更糟)。为什么它没有使用具有较少块并且已经具有我需要的ID的“聚簇索引表”?

4 个答案:

答案 0 :(得分:5)

SQL Server索引是b-trees。非聚集索引仅包含索引列,b树的叶节点是指向适当数据页的指针。聚簇索引是不同的:它的叶节点是数据页本身,聚簇索引的b-tree成为表本身的后备存储;堆不再存在于表中。

您的非聚集索引包含一个可能是整数列。它是一个小而紧凑的索引。您的查询select id from scan有一个覆盖索引:只需检查索引就可以满足查询,这就是正在发生的事情。但是,如果您的查询包含不在索引中的列,假设优化程序选择使用非聚集索引,则需要额外的查找来从集群索引或堆中获取所需的数据页。

要了解正在进行的操作,您需要检查优化程序选择的执行计划:

答案 1 :(得分:2)

聚簇索引通常与堆中的相同数据一样大(假设页面完整性相同)。由于额外的B树级别,它应该使用比堆更多的读取。

CI不能小于堆。我不明白为什么你会这么想。分区的大部分大小(无论是堆还是树)都在数据中。

请注意,较少的物理读取不一定转化为查询速度更快。随机IO可能比顺序IO慢100倍。

答案 2 :(得分:1)

何时使用聚集索引 -

查询注意事项:
1)使用BETWEEN,>,> =,<和< = 2等运算符返回一系列值。返回大的结果集
3)使用JOIN子句;通常这些是外键列
4)使用ORDER BY或GROUP BY子句。 ORDER BY或GROUP BY子句中指定的列的索引可能不需要数据库引擎对数据进行排序,因为行已经排序。这提高了查询性能。

列注意事项: 考虑具有以下一个或多个属性的列: 1)是唯一的或包含许多不同的值 2)定义为IDENTITY,因为该列保证在表中是唯一的 3)经常用于对从表中检索的数据进行排序

对于以下属性,聚簇索引不是一个好的选择: 1)经常变化的列 2)宽键

何时使用非聚集索引

查询注意事项:
1)使用JOIN或GROUP BY子句。在连接和分组操作中涉及的列上创建多个非聚簇索引,并在任何外键列上创建聚簇索引 2)不返回大结果集的查询
3)包含经常涉及查询的搜索条件的列,例如WHERE子句,返回完全匹配

列注意事项
考虑具有以下一个或多个属性的列:
1)覆盖查询。有关更多信息,请参阅包含列的索引
2)如果聚集索引用于其他列,则有许多不同的值,例如姓氏和名字的组合 3)经常用于对从表中检索的数据进行排序

数据库注意事项:
1)具有较低更新要求的数据库或表,但是大量数据可以从许多非聚簇索引中受益,以提高查询性能。
2)包含大量更新表的联机事务处理应用程序和数据库应避免过度索引。此外,索引应该是窄的,即尽可能少的列。

答案 3 :(得分:0)

尝试运行

DBCC DROPCLEANBUFFERS

在查询之前......

如果你真的想比较它们。 在优化查询时,物理读取与逻辑读取的含义不同