聚集索引应该放在什么列?

时间:2009-09-17 16:57:25

标签: sql sql-server database-design indexing

最近,我一直在阅读所有类型的索引,主要建议是将聚簇索引放在表的主键上,但如果主键实际上没有在查询中使用(通过选择或加入)只是出于纯粹的关系目的,所以在这种情况下,它不会被查询。例如,我说有一个car_parts表,它包含3列,car_part_idcar_part_nocar_part_titlecar_part_id是唯一的主键标识列。在这种情况下,car_part_no也是唯一的,很可能是car_part_titlecar_part_no是最受查询的内容,因此将聚簇索引放在该列而不是car_part_id上是否有意义?问题的基础是什么列实际上应该具有聚集索引,因为您只允许其中一个?

5 个答案:

答案 0 :(得分:8)

当且仅当索引中最左侧的键被过滤时,查询优化器才能使用聚簇或非聚类索引。因此,如果您在列(A,B,C)上定义索引,B=@bC=@cB=@b AND C=@c上的WHERE条件将无法完全利用索引(请参阅注释)。这也适用于加入条件。包含A的任何WHERE过滤器都会考虑索引:A=@aA=@a AND B=@bA=@a AND C=@cA=@a AND B=@b AND C=@c

因此,在您的示例中,如果您将part_no上的clustred索引作为最左侧的键,则查找特定part_id的查询将使用索引和a part-id上必须存在单独的非聚集索引。

现在关于许多索引应该是 clustered 的问题。如果您有多个查询模式具有相同的重要性和频率,并且在所需的密钥方面相互矛盾(例如 part_nopart_id的频繁查询然后考虑其他因素:

  • width 所有其他非聚集索引将聚簇索引键用作查找键。因此,如果您选择一个宽键(比如两个uniquidentifier列),那么您将使所有其他索引更宽,从而消耗更多空间,生成更多IO并减慢所有内容。因此,从读取的角度来看,在等于好的密钥之间,选择最窄的密钥作为聚类,并使更宽的密钥成为非聚集的。
  • 争用:如果您有特定的插入和删除模式,请尝试将它们物理分离,以便它们出现在聚集索引的不同部分。例如。如果表充当一个队列,其中所有插入位于一个逻辑端,所有删除位于另一个逻辑端,请尝试布置聚簇索引,以使物理顺序与此逻辑顺序匹配(例如,排队顺序)。
  • 分区:如果表非常大并且您计划部署分区,则分区键必须是聚簇索引。典型示例是使用滑动窗口分区方案存档的历史数据。即使实体有一个逻辑主键,如'entity_id',clustred索引也是由datetime列完成的,该列也用于分区函数。
  • 稳定性:经常更改的密钥是群集密钥的不良候选者,因为每次更新群集密钥值并强制所有非群集索引更新查找他们存储的关键。由于群集密钥的更新也可能将记录重定位到不同的页面,因此可能导致聚簇索引碎片化。

注意:不是完全杠杆,因为有时引擎会选择非聚集索引而不是聚集索引而不是聚簇索引,因为它更窄,因此页面更少扫描。在我的示例中,如果({1}}上有(A,B,C)和WHERE过滤器的索引以及查询项目B=@b,则索引可能会被使用但不会被用作搜索,扫描,因为它仍然比完整的集群扫描更快(更少的页面)。

答案 1 :(得分:4)

当您查询数据范围时,聚簇索引很好。例如

SELECT * FROM theTable WHERE age BETWEEN 10 AND 20

聚簇索引按计算机磁盘上的特定顺序排列行。这就是为什么年龄= 10的行将彼此相邻,之后会有年龄= 11的行等等。

如果您有精确的选择,请执行以下操作:

SELECT * FROM theTable WHERE age = 20

非聚集索引也很好。它不会重新排列计算机磁盘上的数据,但会构建一个特殊的树,其中包含指向所需行的指针。

因此,它在很大程度上取决于您执行的查询类型。

答案 2 :(得分:4)

Kimberly Tripp始终是关于索引的见解的最佳来源之一。

请参阅她的博客文章“Ever-increasing clustering key - the Clustered Index Debate - again!”,其中她非常清楚地列出并解释了良好群集密钥的主要要求 - 它必须是:

  • 唯一
  • 精细
  • 静态

最重要的是,如果你可以管理:

  • 不断增加

考虑到所有这些因素,INT IDENTITY(如果您确实需要超过20亿行,则为BIGINT IDENTITY)在绝大多数情况下都是最佳选择。

许多人没有意识到的一件事(因此在做出选择时没有考虑到)是集群密钥(构成聚集索引的所有列)将被添加到每个以及表格中每个非聚集索引的每个索引条目 - 因此“狭义”要求变得格外重要!

此外,由于聚类键用于书签查找(在非聚集索引中找到行时查找实际数据行),因此“唯一”要求也变得非常重要。实际上非常重要的是,如果你选择一个(一组)列不保证是唯一的,SQL Server将为每一行添加一个4字节的唯一文件 - >从而使您的每个聚簇索引键都更宽;绝对不是一件好事。

马克

答案 3 :(得分:2)

请记住使用模式;如果你几乎总是在car_part_no上查询数据库,那么将它集群在该列上可能是有益的。

但是,不要忘记加入;如果您经常加入表并且联接使用car_part_id字段,那么您有充分的理由将集群保留在car_part_id上。

要记住的其他事项(在这种情况下更少,但通常在考虑聚簇索引时)是聚集索引将隐式出现在表的每个其他索引中;因此,例如,如果您要索引car_part_title,那么该索引也将隐式包含car_part_id。这可能会影响索引是否覆盖查询,还会影响索引占用的磁盘空间(这会影响内存使用情况等)。

答案 4 :(得分:1)

聚集索引应该放在查询次数最多的列上。这包括连接,因为连接必须像直接查询一样访问表,并找到指示的行。

如果应用程序发生更改,您可以随时重建索引,并且发现需要优化具有不同索引结构的表。

有关确定表格集群内容的一些其他指南,请访问MSDN:Clustered Index Design Guidelines