25

最近我在数据库中发现了几个没有定义聚集索引的表。但是定义了非聚集索引,所以它们在 HEAP 上。

在分析中,我发现 select 语句正在对非聚集索引中定义的列使用过滤器。

这些表上没有聚集索引会影响性能吗?

4

6 回答 6

56

很难比 SQL Server MVP Brad McGehee更简洁地说明这一点:

根据经验,每个表都应该有一个聚集索引。通常,但并非总是如此,聚集索引应该位于单调增加的列上——例如标识列,或值增加的其他列——并且是唯一的。在许多情况下,主键是聚集索引的理想列。

BOL回应了这种观点:

除了少数例外,每个表都应该有一个聚集索引。

这样做的原因有很多,主要是基于聚集索引对存储中的数据进行物理排序这一事实。

  • 如果您的聚集索引在单个列上单调增加,则插入会在您的存储设备上按顺序发生,并且不会发生页面拆分。

  • 当索引值唯一时,聚集索引对于查找特定行非常有效,例如基于主键选择行的常见模式。

  • 聚集索引通常允许对经常搜索值范围( 、 等)的列进行有效between查询>

  • 聚类可以加快数据通常按特定列或列排序的查询。

  • 可以根据需要重建或重组聚集索引以控制表碎片。

  • 这些好处甚至可以应用于视图

您可能不希望在以下位置创建聚集索引:

  • 具有频繁数据更改的列,因为 SQL Server 必须随后对存储中的数据进行物理重新排序。

  • 已被其他索引覆盖的列。

  • 宽键,因为聚集索引也用于非聚集索引查找。

  • GUID 列,它们大于标识,并且还有效地随机值(不太可能被排序),但newsequentialid()可用于帮助减轻插入期间的物理重新排序。

  • 使用(没有聚集索引的表)的一个罕见原因是,如果始终通过非聚集索引访问数据,并且已知 RID(SQL Server 内部行标识符)小于聚集索引键。

由于这些和其他考虑因素,例如您的特定应用程序工作负载,您应该仔细选择聚集索引,以便为您的查询获得最大收益。

另请注意,当您在 SQL Server 中的表上创建主键时,默认情况下它将创建一个唯一的聚集索引(如果它还没有)。这意味着,如果您发现一个没有聚集索引但有主键的表(所有表都应该),则开发人员之前已决定以这种方式创建它。您可能希望有一个令人信服的理由来改变这一点(正如我们所见,其中有很多)。添加、更改或删除聚集索引需要重写整个表和任何非聚集索引,因此在大型表上这可能需要一些时间。

于 2012-08-06T20:51:41.563 回答
4

我不会说“每个表都应该有一个聚集索引”,我会说“仔细查看每个表以及它们是如何被访问的,如果有意义的话,尝试在它上面定义一个聚集索引”。这是一个加号,就像小丑一样,每张桌子只有一个小丑,但你不必使用它。其他数据库系统没有这个,至少在这种形式下,顺便说一句。

Putting clustered indices everywhere without understanding what you're doing can also kill your performance (in general, the INSERT performance because a clustered index means physical re-ordering on the disk, or at least it's a good way to understand it), for example with GUID primary keys as we see more and more.

So, read Tim Lehner's exceptions and reason.

于 2012-08-07T16:38:04.157 回答
1

是的,您应该在表上拥有聚集索引。这样所有非聚集索引都会以更好的方式执行。

于 2012-08-03T01:45:40.153 回答
1

性能是一个毛茸茸的大问题。确保您正在针对正确的事情进行优化。

免费的建议总是物有所值,并且没有什么可以替代实际的实验。

索引的目的是找到匹配的行并在找到时帮助检索数据。

搜索条件上的非聚集索引将有助于查找行,但需要进行额外的操作才能获取行的数据。

如果没有聚集索引,SQL 使用内部 rowId 来指向数据的位置。

但是,如果表上有聚集索引,则该 rowId 将替换为聚集索引中的数据值。

因此不需要读取行数据的步骤,并且会被索引中的值覆盖。

即使聚集索引的选择性不是很好,如果这些键经常是请求的大部分或全部结果 - 将它们作为非聚集索引的叶子可能会有所帮助。

于 2012-08-06T20:13:30.950 回答
0

考虑使用clustered index包含大量不同值的 when 列,以避免 SQL Server 需要添加“唯一符”来重复键值

缺点:如果只在聚簇索引中的字段发生变化时,更新记录需要更长的时间。

避免在几乎相同的聚簇索引值上发生许多并发插入的风险的聚簇索引构造

如果聚集索引没有正确构建,或者它不包括将数据返回给调用应用程序所需的所有列,则针对非聚集索引的搜索会显得较慢。如果非聚集索引不包含所有需要的数据,则 SQL Server 将转到聚集索引以获取丢失的数据(通过查找),这将使查询运行速度变慢,因为查找完成行按行。

于 2012-08-03T09:48:46.923 回答
0

是的,每个表都应该有一个聚集索引。聚集索引设置表中数据的物理顺序。您可以将此与商店中按乐队名称和/或按姓氏排序的黄页的音乐排序进行比较。由于这涉及物理订单,因此您只能拥有一个,它可以由许多列组成,但您只能拥有一个。

最好将聚集索引放在经常搜索一系列值的列上。示例是日期范围。当索引值唯一时,聚集索引对于查找特定行也很有效。如果未定义聚簇索引,Microsoft SQL 将自动将聚簇索引放置在 PRIMARY KEY 约束上。

聚集索引不是一个好的选择:

频繁更改的列

  • 这会导致整行移动(因为 SQL Server 必须按物理顺序保持行的数据值)。在数据往往不稳定的大容量事务处理系统中,这是一个重要的考虑因素。

宽键

  • 来自聚集索引的键值被所有非聚集索引用作查找键,因此存储在每个非聚集索引叶条目中。
于 2012-08-06T21:15:00.143 回答