0

我有一系列关于 SQL,特别是 SQL 2005 中的键、索引和约束的问题。我已经使用 SQL 大约 4 年了,但我从来没有能够得到关于这个主题的明确答案,而且在博客文章等上总是有相互矛盾的信息。我创建和使用的大多数时间表只有一个 Identity 列是主键,其他表通过外键指向它。

使用连接表,我没有身份,并在外键列上创建复合主键。以下是我目前的信念的一组陈述,可能是错误的,如果是,请纠正我,以及其他问题。

所以这里是:

据我了解,聚集索引和非聚集索引之间的区别(无论它是否唯一)是聚集索引会影响表中数据的物理顺序(因此表中只能有一个),而非聚集索引构建树数据结构。创建索引时,为什么我应该关心集群与非集群?我什么时候应该使用其中一种?有人告诉我,非聚集索引的插入和删除速度很慢,因为树需要“重建”。我认为聚集索引不会影响性能吗?

我看到主键实际上只是唯一的聚集索引(它们必须聚集吗?)。主键与聚集唯一索引有什么特别之处?

我也见过约束,但我从未使用过它们或真正看过它们。有人告诉我,约束的目的是强制数据完整性,而索引的目的是提高性能。我还读到约束实际上是作为索引实现的,因此它们是“相同的”。这对我来说听起来不对。约束与索引有何不同?

4

5 回答 5

2

正如你所说的那样,聚集索引是关于如何物理存储表中数据的定义,即你有一个使用聚集键排序的 B 树,并且你有叶级别的数据。

另一方面,非聚集索引是单独的树结构,在叶级别只有聚集键(如果表是堆,则为 RID),这意味着当您使用非聚集索引时,您必须使用聚集索引来获取其他列(除非您的请求完全被非聚集索引覆盖,如果您仅请求构成非聚集索引键列的列,则可能发生这种情况)。

什么时候应该使用其中一种?好吧,因为你只能有一个聚集索引,所以在最有意义的列上定义它,即当你大部分时间通过 ID 查找客户端时,在 ID 上定义一个聚集索引。非聚集索引应该在不经常使用的列上定义。

关于性能,更改索引键的插入或更新总是很痛苦,无论它是否是非聚集索引上的聚集索引,因为可能发生页面拆分,这会迫使数据在页面之间移动(移动聚集索引的页面伤害更大,因为您在叶级别有更多数据)。因此,一般规则是避免更改索引键并插入新值,以便它们是连续的。否则,您将遇到碎片,并且必须定期重建索引。

最后,关于约束,根据定义,它们与索引无关,但 SQL Server 选择使用索引来实现它们。例如,目前,唯一约束被实现为索引,但是这可能会在未来的版本中改变(尽管我怀疑这会发生)。索引的类型(是否聚集)取决于您,请记住您只能拥有一个聚集索引。

如果您有更多此类问题,我强烈建议您阅读这本书,它深入涵盖了这些主题。

于 2009-09-10T08:16:38.483 回答
1

您对集群与非集群的假设非常好

似乎主键强制执行非空唯一性,而唯一索引不强制执行非空主与唯一

于 2009-09-10T08:09:01.217 回答
1

是关系数据库理论中的一个逻辑概念——它是一个键(通常也是一个索引),旨在唯一地标识您的任何行。因此它必须是唯一的,并且不能为 NULL。

集群键是 SQL Server 的存储物理概念。它是一个特殊的索引,不仅用于查找等,还定义了表中数据的物理结构。在西欧文化的印刷电​​话簿中(可能除了冰岛),聚集索引将是“姓氏,名字”。

由于集群索引定义了您的物理数据布局,因此您只能拥有其中之一(或者没有 - 但不推荐)。

集群键的要求是:

  • 必须是唯一的(如果不是,SQL Server 将添加一个 4 字节的“唯一性”)
  • 应该是稳定的(永不改变)
  • 应该尽可能小(最好是 INT)
  • 应该不断增加(想想:身份)

默认情况下,SQL Server 将您的主键设置为集群键 - 但如果需要,您可以更改它。另外,请注意:构成集群键的列将被添加到表上每个非聚集索引的每个条目中 - 因此您希望使集群键尽可能小。这是因为集群键将用于执行“书签查找”——如果您在非集群索引中找到了一个条目(例如,一个人的社会安全号码),现在您需要获取整行数据以获取更多详细信息,您需要进行查找,为此,使用了集群键。

关于什么是好的或有用的集群和/或主键存在很大的争论 - 这里有一些优秀的博客文章可供阅读:

马克

于 2009-09-10T08:16:09.013 回答
1

你有几个问题。我将打破其中的一些:

创建索引时,为什么我应该关心集群与非集群?

有时您确实关心行的组织方式。这取决于您的数据以及您将如何使用它。例如,如果您的主键是 a uniqueidentifier,您可能不希望它是CLUSTERED,因为 GUID 值本质上是随机的。这将导致 SQL 在整个表中随机插入行,从而导致页面拆分,从而损害性能。如果您的主键值将始终按顺序递增(int IDENTITY例如),那么您可能希望它是CLUSTERED,因此您的表将始终在最后增长。

主键是CLUSTERED默认的,大多数时候你不必担心它。

有人告诉我,非聚集索引的插入和删除速度很慢,因为树需要“重建”。我认为聚集索引不会影响性能吗?

实际上,情况可能正好相反。 NONCLUSTERED索引作为单独的数据结构保存,但该结构旨在允许进行一些修改而无需“重新构建”。最初创建索引时,您可以指定FILLFACTOR,它指定在索引的每一页上留下多少可用空间。这允许索引在需要进行页面拆分之前容忍一些修改。即使必须发生页面拆分,它也只会影响相邻页面,而不是整个索引。

同样的行为也适用于CLUSTERED索引,但由于CLUSTERED索引存储实际的表数据,因此对索引的页面拆分操作可能会更加昂贵,因为可能需要移动整行(而不是仅键列和索引ROWID中的)。NONCLUSTERED

以下 MSDN 页面讨论FILLFACTOR和页面拆分: http: //msdn.microsoft.com/en-us/library/aa933139 (SQL.80).aspx

主键与聚集唯一索引有什么特别之处? 约束与索引有何不同?

对于这两种情况,我认为更多的是表明你的意图。当您调用某项 a 时PRIMARY KEY,您声明它是识别给定行的主要方法。PRIMARY KEY物理上与 a 不同吗CLUSTERED UNIQUE INDEX?我不知道。行为本质上是相同的,但是使用您的数据库的人可能不清楚您的意图。

Regarding constraints, there are many types of constraints. For a UNIQUE CONSTRAINT, there isn't really a difference between that and a UNIQUE INDEX, other than declaring your intention. There are other types of constraints that do not map directly to a type of index, such as CHECK constraints, DEFAULT constraints, and FOREIGN KEY constraints.

于 2009-09-10T08:19:59.560 回答
0

我没有时间深入回答这个问题,所以这里有一些我脑海中的信息:

您对聚集索引是正确的。它们根据聚集索引的排序顺序重新排列物理数据。您可以将聚集索引专门用于范围限制查询(例如日期之间)。

默认情况下,PK 是集群的,但并非必须如此。这只是一个默认设置。PK 应该是该行的 UID。

约束可以实现为索引(例如,唯一约束),但也可以实现为默认值。

于 2009-09-10T08:07:19.190 回答