【问题标题】:SQL 2005: Keys, Indexes and Constraints QuestionsSQL 2005:键、索引和约束问题
【发布时间】:2009-09-10 07:57:08
【问题描述】:

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

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

所以这里是:

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

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

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

【问题讨论】:

    标签: sql-server primary-key indexing constraints clustered-index


    【解决方案1】:

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

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

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

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

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

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

    【讨论】:

      【解决方案2】:

      您对clustered vs non-clustered 的假设非常好

      似乎主键强制非空唯一性,而唯一索引不强制非空primary vs unique

      【讨论】:

        【解决方案3】:

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

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

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

        集群键的要求是:

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

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

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

        马克

        【讨论】:

          【解决方案4】:

          您有几个问题。我会分解其中的一些:

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

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

          默认情况下主键是CLUSTERED,大多数时候你不必担心。

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

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

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

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

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

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

          关于约束,有很多类型的约束。对于UNIQUE CONSTRAINT,它与UNIQUE INDEX 之间并没有真正的区别,只是表明了你的意图。还有其他类型的约束不直接映射到某种索引,例如CHECK 约束、DEFAULT 约束和FOREIGN KEY 约束。

          【讨论】:

            【解决方案5】:

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

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

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2014-10-01
              • 2011-05-25
              • 1970-01-01
              • 1970-01-01
              • 2013-06-09
              • 1970-01-01
              • 2011-04-28
              相关资源
              最近更新 更多