4

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

SELECT id FROM scan

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

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

在此处输入图像描述

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

4

4 回答 4

5

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

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

要了解发生了什么,您需要检查优化器选择的执行计划:

于 2014-11-28T18:14:15.773 回答
2

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

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

请注意,较少的物理读取并不一定意味着查询更快。随机 IO 可能比顺序 IO 慢 100 倍。

于 2014-11-28T18:06:52.977 回答
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) 包含大量更新表的在线事务处理应用程序和数据库应避免过度索引。此外,索引应该很窄,即尽可能少的列。

于 2016-05-17T17:00:52.020 回答
0

尝试运行

DBCC DROPCLEANBUFFERS

在查询之前...

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

于 2014-11-28T18:09:32.767 回答