聚簇索引必须唯一吗?


83

如果聚集索引不是唯一的,会发生什么?因为插入的行流到某种“溢出”页面,会导致性能下降吗?

它是“独特的”吗?使其独特的最佳方法是什么?

我之所以问是因为我当前正在使用聚集索引将表划分为逻辑部分,但是性能如此一般,最近我得到使聚集索引唯一的建议。我想要第二点意见。

谢谢!

Answers:


90

他们不具有是唯一的,但可以肯定的是鼓励。
我还没有遇到过要在非唯一列上创建配置项的方案。

如果在非唯一列上创建配置项会怎样?

如果聚集索引不是唯一索引,则SQL Server通过添加一个内部生成的值(称为“唯一符”)使所有重复键成为唯一键

这会导致性能下降吗?

添加唯一符肯定会增加一些计算和存储开销。
这种开销是否显着取决于几个因素。

  • 该表包含多少数据。
  • 插入率是多少?
  • 一次选择中使用CI的频率(当不存在覆盖索引时,几乎总是如此)。


正如Remus在评论中指出的那样进行编辑,确实存在一些使用案例,在这些案例中,创建非唯一的CI将是一个合理的选择。我没有遇到那种情况只是表明我自己缺乏接触或能力(选择您的选择)。


30
+1会导致您所说的一切都是正确的,但只想补充一下:当对特定(非唯一)列进行范围扫描时,非唯一CI非常普遍。
雷木斯·鲁萨努

@Remus Rusanu:我当时正在考虑在我的场景陈述中添加一个免责声明,但这并不意味着什么。感谢您指出一个可能有用的场景。
Lieven Keersmaekers,2010年

4
@Remus:您是说在一个特殊的情况下,您有一个非唯一的列(如“ Departmentid”),在其中查询诸如“ DepartmentId BETWEEN 1 and 100”之类的内容吗?编辑啊,我明白你的意思了,是的,日志记录表中的日期列也是一个很好的例子。
littlegreen 2010年

嘿,我有一个事件流表,其中存在多个具有相同“ AggregateId”的行,这是GUID类型的列。在表上执行的唯一查询是获取给定AggregateId的所有事件。我想知道这应该是聚集索引还是非聚集索引?
C

@ShayanC-如果将检索性能作为您的主要目标,那么我将其作为CI来检索给定ID的所有行时可能节省IO。但是,与所有性能方案一样,唯一确定的方法是进行度量。
Lieven Keersmaekers

32

我想了解一下索引女王,金伯利·特里普(Kimberly Tripp)在这个话题上怎么说:

由于一些原因,我将从对群集密钥的建议开始。首先,这是一个容易做出的决定,其次,及早做出此决定有助于主动防止某些类型的分裂。如果可以防止某些类型的基表碎片,则可以最大程度地减少一些维护活动(要求在SQL Server 2000中进行某些维护,而在SQL Server 2005中进行较少的维护)要求表处于脱机状态。好的,我稍后再讨论。

让我们从我在集群密钥中寻找的关键事物开始:

* Unique
* Narrow
* Static

为什么独特? 集群键应该是唯一的,因为集群键(如果存在)将用作所有非集群索引中的查找键。以书后的索引为例-如果您需要查找索引条目指向的数据-否则该条目(索引条目)必须唯一,否则,该索引条目将是您要查找的索引条目?因此,当您创建聚簇索引时-它必须是唯一的。但是,SQL Server不需要在唯一列上创建群集密钥。您可以在任何所需的列上创建它。在内部,如果群集密钥不是唯一的,则SQL Server将通过向数据添加4字节整数来“唯一化”它。因此,如果聚集索引是在非唯一的事物上创建的,那么不仅在创建索引时会产生额外的开销,还会浪费磁盘空间,

资料来源: 群集主题辩论不断增加-再次!


尽管有一个问题,皇后区还是建议使用新闻序列对数据进行唯一化,但是如果您未指定,SQL Server会生成自己的唯一化器。那么,仍然有任何理由添加您自己的顺序ID吗?
littlegreen 2010年

2
@littlegreen:她说,如果您坚持使用GUID(对于在聚簇索引中使用确实很不好),那么至少要使用它newsequentialid()来获得几乎是序列化的GUID。但是可以:如果添加自己的唯一ID(我总是更喜欢INT IDENTITY),那么您手头就有该值,就可以使用它(例如,建立FK关系)。SQL Server添加的独特性对您不可见,因此它们只是您无法利用的开销。
marc_s

我懂了。嗯,这将是支持(CompanyID,DepartmentID,id INT IDENTITY)聚集索引而不是仅前两个索引的参数。谢谢!
littlegreen 2010年

1
@littlegreen:更好-使聚簇索引位于(ID INT IDENTITY)上,并将其他字段(如果需要)放入单独的非聚簇索引中。聚簇索引应该尽可能小-毕竟,聚簇索引列也要添加到该表上每个非聚簇索引的每个条目中,所以不要将字节浪费在宽聚簇上指数!
marc_s

1
是的,但是我失去了对所有部门数据进行分组的好处,并且能够一次插入/删除/检索整个部门。我的数据将变得分散,并且整个部门甚至整个公司的插入/删除速度将变慢。我的查询只一次在单个公司上运行,并且经常需要更新整个数据集。
littlegreen 2010年

9

聚簇索引必须唯一吗?

他们没有,有时候,如果不是,那会更好。

考虑一个表,该表具有半随机,唯一的EmployeeId和每个员工的DepartmentId:如果select语句为

SELECT * FROM EmployeeTable WHERE DepartmentId=%DepartmentValue%

那么DepartmentId即使聚簇索引不是唯一索引(如果不是唯一索引),它也是对性能最好的选择(对性能最好,因为它可以确保给定DepartmentId中的所有记录都是聚簇的)。


你有参考吗?

聚集索引设计指南例如,它说,

除少数例外,每个表都应在一个或多个列上定义一个聚集索引,该聚集索引提供以下内容:

  • 可用于经常使用的查询。
  • 提供高度的独特性。
  • 可用于范围查询。

例如,我对“高度唯一性”的理解是,如果大多数查询都想选择给定城镇内的记录,那么选择“国家”作为聚集索引是不好的。


是的,直到现在我还是这么想的,但是我也得到了完全相反的建议,所以我想知道那是真的。你有参考吗?
littlegreen 2010年

@littlegreen我编辑了答案以尝试回答您的问题。
ChrisW 2010年

谢谢。是的,我明白你的意思了。但是,如果您要定期一次插入整个国家/地区,则对(国家/地区,城镇)的聚集索引在我看来会很麻烦,因为它需要对数据进行排序。另一方面,在插入之前进行排序不会带来太多麻烦……
littlegreen 2010年

3
当然,在您的示例中,最好在{DepartmentID,EmployeeID}上使用唯一的聚集索引?当您现有的字段将以更少的开销提供唯一性(可能是一个四字节的INT)并可能让您仅在索引中运行更多查询时,为什么系统会创建一个唯一性?
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.