Sql 聚集索引应该放在哪一列上?

Sql 聚集索引应该放在哪一列上?,sql,sql-server,database-design,indexing,Sql,Sql Server,Database Design,Indexing,最近,我一直在阅读各种类型的索引,主要的建议是将聚集索引放在表的主键上,但是如果主键实际上没有在查询中使用(通过选择或连接),而只是出于纯粹的关系目的而放置,那么在本例中它不会被查询。例如,假设我有一个car\u parts表,它包含3列,car\u part\u id,car\u part\u no,和car\u part\u titlecar\u part\u id是唯一的主键标识列。在这种情况下,car\u part\u no也是唯一的,很可能是car\u part\u titlecar\

最近,我一直在阅读各种类型的索引,主要的建议是将聚集索引放在表的主键上,但是如果主键实际上没有在查询中使用(通过选择或连接),而只是出于纯粹的关系目的而放置,那么在本例中它不会被查询。例如,假设我有一个
car\u parts
表,它包含3列,
car\u part\u id
car\u part\u no
,和
car\u part\u title
car\u part\u id
是唯一的主键标识列。在这种情况下,
car\u part\u no
也是唯一的,很可能是
car\u part\u title
car\u part\u no
是查询最多的对象,因此将聚集索引放在该列上而不是
car\u part\u id
,难道没有意义吗?这个问题的基本问题是,哪一列实际上应该有聚集索引,因为您只被允许使用其中的一个?

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

如果应用程序发生更改,并且您发现需要使用不同的索引结构优化表,那么您可以在以后重新生成索引


在MSDN上可以找到一些关于决定表的集群的附加指南:。

记住使用模式;如果您几乎总是在car\u part\u no上查询数据库,那么将其聚集在该列上可能是有益的

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


要记住的另一件事(在本例中不是这样,但通常在考虑聚集索引时)是聚集索引将隐式地出现在表上的每个其他索引中;例如,如果要为car\u part\u title编制索引,该索引还将隐式包含car\u part\u id。这会影响索引是否覆盖查询,也会影响索引将占用多少磁盘空间(这会影响内存使用等)。

查询数据范围时,聚集索引很好。比如说

SELECT * FROM theTable WHERE age BETWEEN 10 AND 20
聚集索引在计算机磁盘上按特定顺序排列行。这就是为什么年龄=10的行彼此相邻,然后是年龄=11的行,以此类推

如果您有“精确选择”,请如下所示:

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


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

当且仅当索引中最左边的键被过滤时,查询优化器才可以使用聚集索引或非聚集索引。因此,如果在列(A、B、C)上定义索引,则
B=@B
、on
C=@C
或on
B=@B和C=@C
上的WHERE条件将无法充分利用索引(请参见注释)。这也适用于联接条件。凡包含<代码> A/<代码>的任何过滤器都将考虑索引:<代码> A>=A<代码>或<代码> A= @ A和B= @ B<代码>或>代码> A= @ A和C=@ C < /代码>或<代码> A= @ A和B=@ B和C=@ C < /代码> . 因此,在您的示例中,如果将
part\u no
上的聚集索引作为最左边的键,则查找特定
part\u id
的查询将不会使用该索引,并且
part id
上必须存在单独的非聚集索引

现在我们来讨论一下,在众多索引中,哪些应该是聚集索引。如果您有几个重要性和频率大致相同的查询模式,并且在所需的键方面相互矛盾(例如,
part\u no
part\u id
的频繁查询),那么您需要考虑其他因素:

  • 宽度:聚集索引键被所有其他非聚集索引用作查找键。因此,如果您选择一个宽键(比如两个未限定的列),那么您将使所有其他索引变宽,从而消耗更多的空间,生成更多的IO,并降低所有操作的速度。因此,从读取的角度来看,在同等好的键之间,选择最窄的一个作为聚集键,并将较宽的键设置为非聚集键
  • 争用:如果您有特定的插入和删除模式,请尝试将它们物理地分开,以便它们出现在聚集索引的不同部分。例如,如果表充当一个队列,所有插入在一个逻辑端,所有删除在另一个逻辑端,请尝试布局聚集索引,以便物理顺序与此逻辑顺序匹配(例如排队顺序)
  • 分区:如果表非常大,并且您计划部署分区,那么分区键必须是聚集索引。典型的例子是使用滑动窗口分区方案归档的历史数据。即使实体有一个逻辑主键,比如“entity_id”,集群索引也是由一个datetime列完成的,该列也用于分区函数
  • 稳定性:经常更改的键对于聚集键来说不是很好的候选键,因为每个键都会更新聚集键值,并强制所有非聚集索引更新它们存储的查找键。由于更新聚集键也可能会将记录重新定位到不同的页面,因此可能会导致聚集索引上出现碎片
注意:没有充分利用,因为有时引擎会选择非聚集索引而不是聚集索引进行扫描,因为聚集索引更窄,因此要扫描的页面更少。在我的示例中,如果在(A,B,C)上有一个索引,在
B=@B
上有一个WHERE filter,并且查询项目
C
,则该索引很可能会被使用,但不会用作搜索或扫描,因为它仍然是fas