为什么NonClustered索引扫描比Clustered Index扫描更快?
据我所知,堆表是没有聚集索引且没有物理顺序的表。 我有一个堆表“扫描”与120K行,我正在使用此选择:
SELECT id FROM scan
如果我为列“id”创建非聚集索引,则可以获得223个物理读取 。 如果我删除非聚集索引并改变表格以使我的主键(以及我的聚集索引)成为“id”,那么我得到515个物理读取 。
如果聚簇索引表是这样的图片:
为什么Clustered Index Scans像桌面扫描一样工作? (或者在检索所有行的情况下更糟糕)。 为什么它不使用具有较少块的“聚簇索引表”,并且已经有我需要的ID?
SQL Server索引是b树。 非聚簇索引只包含索引列,而b树的叶节点是指向适当数据页面的指针。 聚集索引是不同的:它的叶节点是数据页面本身,聚簇索引的B树成为表本身的后备存储; 桌子上的堆不再存在了。
您的非聚集索引包含一个大概为整数的列。 这是一个小而紧凑的索引。 您select id from scan
查询select id from scan
具有覆盖索引:仅通过检查索引就可以满足查询,这就是发生的情况。 但是,如果您的查询包含不在索引中的列,假设优化器选择使用非聚集索引,则需要额外的查找来从集群索引或堆中提取所需的数据页。
要理解正在发生的事情,您需要检查优化器选择的执行计划:
聚集索引通常大约与堆中的相同数据一样大(假设页面已满)。 由于额外的B-tree级别,它应该只使用比堆更多的读取。
CI不能小于堆。 我不明白你为什么会这么想。 大部分分区的大小(不管是堆还是树)都在数据中。
请注意,较少的物理读取不一定会转化为查询速度更快。 随机IO可以比顺序IO慢100倍。
何时使用聚簇索引 -
查询注意事项:
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)包含大量更新表的联机事务处理应用程序和数据库应避免索引过多。 此外,索引应该很窄,即尽可能少的列。
上一篇: Why NonClustered index scan faster than Clustered Index scan?