最近我在数据库中找到了几个没有定义聚类索引的表。 但是定义了非聚集索引,因此它们处于HEAP状态。
在分析中,我发现select语句对非聚集索引中定义的列使用了过滤器。
这些表上没有聚簇索引会影响性能吗?
答案 0 :(得分:49)
很难比SQL Server MVP Brad McGehee更简洁地说明这一点:
As a rule of thumb, every table should have a clustered index. 通常,但并非总是如此,聚集索引应位于单调增加的列上 - 例如标识列或值增加的其他列 - 和是独特的。在许多情况下,主键是聚簇索引的理想列。
BOL回应了这种观点:
除了少数例外,每个表都应该有一个聚簇索引。
这样做的原因很多,主要是基于群集索引在物理上对存储中的数据进行排序这一事实。
如果您的聚簇索引在单个列上单调增加,则会在您的存储设备上按顺序进行插入,并且不会发生页面拆分。
当索引值唯一时,聚簇索引可有效查找特定行,例如基于主键选择行的常见模式。
聚集索引often允许对经常搜索值范围(between
,>
等)的列进行有效查询。
群集可以加快数据通常按特定列排序的查询。
可以根据需要重建或重组聚簇索引,以控制表碎片。
这些好处甚至可以是applied to views。
您可能不希望拥有聚集索引:
频繁更改数据的列,因为SQL Server必须在物理上对存储中的数据进行重新排序。
其他索引已涵盖的列。
宽键,因为聚簇索引也用于非聚集索引查找。
GUID列,它们大于标识并且也是有效的随机值(不太可能被排序),但newsequentialid()
可用于帮助减轻插入期间的物理重新排序。
使用heap(没有聚簇索引的表)的一个罕见原因是,数据总是通过非聚簇索引访问,并且已知RID(SQL Server内部行标识符)小于聚集索引键。
由于这些和其他注意事项(例如您的特定应用程序工作负载),您应该仔细选择聚簇索引以获得查询的最大好处。
另请注意,在SQL Server中的表上创建主键时,默认情况下会创建唯一的聚簇索引(如果它还没有)。这意味着如果您发现一个表没有聚集索引,但确实有一个主键(因为所有表都应该),开发人员之前已决定以这种方式创建它。您可能希望有一个令人信服的理由来改变它(其中有很多,正如我们所见)。 添加,更改或删除聚簇索引需要重写整个表以及任何非聚簇索引,因此这可能需要一些大型表。
答案 1 :(得分:3)
我不会说“每个表都应该有一个聚簇索引”,我会说“仔细查看每个表以及如何访问它们并尝试在其上定义聚簇索引如果它有意义”。这是一个加分,就像一个小丑,你每桌只有一个小丑,但你不必须使用它。其他数据库系统没有这个,至少在这种形式下,BTW。
将聚簇索引放在任何地方而不了解你正在做什么也会破坏你的性能(一般来说,INSERT性能是因为聚簇索引意味着在磁盘上进行物理重新排序,或者至少它是理解它的好方法) ,例如我们看到越来越多的GUID主键。
所以,请阅读Tim Lehner的例外与理由。
答案 2 :(得分:1)
是的,您应该在表上拥有聚簇索引。所有非聚簇索引都以更好的方式执行。
答案 3 :(得分:1)
性能是一个很大的问题。确保你正在优化正确的事情。
免费咨询总是值得它的价格,并且没有替代实际的实验。
索引的目的是查找匹配的行,并在找到时帮助检索数据。
搜索条件上的非聚集索引将有助于查找行,但需要执行其他操作才能获取行的数据。
如果没有聚簇索引,SQL使用内部rowId指向数据的位置。
但是,如果表上存在聚簇索引,则该rowId将被聚簇索引中的数据值替换。
因此,不需要读取行数据的步骤,并且将由索引中的值覆盖。
即使聚簇索引不是很有选择性,如果这些键经常被请求的大部分或全部结果 - 将它们作为非聚集索引的叶子可能会有所帮助。
答案 4 :(得分:1)
是的,每个表都应该有一个聚簇索引。聚簇索引设置表中数据的物理顺序。您可以将其与商店中的音乐排序,乐队名称和/或按姓氏排序的黄页进行比较。由于这涉及物理订单,您只能拥有一个,它可以由多列组成,但您只能有一个。
最好将聚簇索引放在经常搜索一系列值的列上。示例是日期范围。当索引值是唯一的时,聚簇索引对于查找特定行也是有效的。 如果未定义聚簇索引,Microsoft SQL将自动将聚簇索引放在PRIMARY KEY约束上。
群集索引不适合:
经常更改的列
宽键
答案 5 :(得分:0)
当包含大量不同值的列时,请考虑使用clustered index
,以避免SQL Server添加“uniqueifier”以复制键值
缺点:只有当聚类索引中的字段发生更改时,才需要更长的时间来更新记录。
避免群集索引构造,因为在几乎相同的群集索引值存在许多并发插入的风险
对非聚集索引的搜索将显得较慢,因为聚簇索引未正确构建,或者它不包括将数据返回给调用应用程序所需的所有列。如果非聚集索引不包含所有需要的数据,那么SQL Server将转到聚集索引以获取丢失的数据(通过查找),这将使查询在查找完成时运行速度变慢按行。