【问题标题】:Where to place a primary key放置主键的位置
【发布时间】:2010-10-09 04:40:03
【问题描述】:

据我所知,SQL Server 2008 只允许每个表有一个聚集索引。为了这个问题,假设我有一个用户提交的故事列表,其中包含以下列。

ID(整数,主键)
标题 (nvarchar)
网址 (nvarchar)
UniqueName (nvarchar) 这是 url slug (blah-blah-blah)
CategoryID (int, FK to Category table)

大多数情况下,故事永远不会通过 ID 进行查询。大多数查询将由 CategoryID 或 UniqueName 完成。

我是索引新手,所以我认为最好在此表上放置 2 个非聚集索引。一个在 UniqueName 上,一个在 CategoryID 上。在阅读了一些关于索引的内容之后,似乎在 UniqueName 上创建一个聚集索引会非常有益。考虑到 UniqueName is... unique 将主键放在 UniuqeName 上并摆脱 ID 字段是否有利?至于 CategoryID,我认为非聚集索引就可以了。

谢谢。

【问题讨论】:

    标签: sql sql-server-2008 indexing


    【解决方案1】:

    首先,您可以将聚集索引放在唯一名称上,它不必放在 id 字段上。如果你很少或没有加入这个表,你可以摆脱 id。无论如何,我会在唯一名称字段上放置一个唯一索引(您可能会发现这样做并不像您想象的那么唯一!)。

    如果你做了很多加入,我会保留 id 字段,它更小,加入更有效。

    既然你说你是索引新手,我要指出,虽然主键在定义时会自动创建索引,但外键不会。您几乎总是希望索引您的外键字段。

    【讨论】:

    • 我不知道你可以拆分PK和聚集索引,非常感谢。
    • 聚集索引是默认的主键,但你不必这样做。
    【解决方案2】:

    只是出于习惯,我总是像 PK 一样创建一个身份字段“ID”。它使事情保持一致。如果所有“主”表都有一个名为“ID”的字段,即 INT Identity,那么 PK 是什么总是显而易见的。此外,如果我需要创建一个桥实体,我将存储两个(或更多)INT 类型的列,而不是 nvarchar() 类型。因此,在您的示例中,我会将 ID 保留为 PK,并在 UniqueName 上创建一个唯一索引。

    【讨论】:

      【解决方案3】:

      数据按聚集键的顺序存储;如果您要通过这些字段之一对数据进行密钥检索,那么使用假设值没有明显碎片化是有利的,这会降低插入性能。

      另一方面,如果此表在 ID 上连接到很多,则将聚簇键保留在 PK 上可能更有意义。

      【讨论】:

        【解决方案4】:

        通常,最好在标识键上为表建立索引并将其用作聚集索引。这里有一个简单的经验法则

        不要使用有意义的列作为主索引

        这样做的原因是,通常在有意义的列上使用 PK 往往会引起维护问题。这是一个经验法则,因此可以在这种情况下被覆盖,但通常最好从由(聚集的)无意义的标识列索引的每个表的假定默认位置开始工作。这样对于连接往往更有效,并且由于它通常是大多数 DBA 将采用的默认设计,因此不会引起任何关注或产生任何问题,因为它们的系统不像下一个 DBA 可能假设的那样。毫无意义的 PK 总是更灵活,更容易适应不断变化的环境

        何时覆盖规则?仅当您确实设想到性能问题时。对于大多数在适当索引的现代硬件上具有合理负载的数据库,如果您不通过对最佳索引进行聚类来从它们中挤出最后一毫秒的性能,那么您将不会遇到任何问题。 DBA 和程序员周期比 CPU 周期要昂贵得多,如果您通过采用不同的策略仅将查询中的奇数毫秒左右缩短,那么它就是不值得的。但是,如果您正在查看接近一百万行的表,那就另当别论了。这在很大程度上取决于具体情况,但一般来说,如果我正在设计一个包含少于 100,000 行表的数据库,我会非常倾向于设计灵活性、易于编写稳定查询以及任何其他设计者希望看到的原则。超过一百万行然后我设计性能。在 10 万到 100 万之间,这是一个判断问题。

        【讨论】:

        • 如果你要在激烈的宗教讨论中争论一方,你至少应该提到另一个立场是存在的,并且至少在某种程度上是可以辩护的。
        • 我对此并不信奉,您的教条会认为您应该始终使用身份 int PK,我真的不认为这是真的,但假设您将使用除非您有其他理由,否则身份 PK 是一个安全的立场......
        • 更糟糕的情况是你的设计师没有考虑过这个问题,而是根据心情随意混合身份和有意义的键 - 这比任何一个都更糟糕
        【解决方案5】:

        根本没有必要或没有必要拥有一个聚集索引,主键或其他。与所有索引策略一样,它是一种性能优化工具,应该在使用它可以获得改进时应用。

        如前所述,因为表是根据聚集索引键进行物理排序的,所以这是一种汉兰达情况:只能有一个!

        聚集索引主要用于以下情况:

        • 您经常需要检索给定列的值在一个范围内的一组行,因此通常作为 BETWEEN 子句主题的列很有趣;或
        • 表格中的大多数单行命中都发生在可由键值的子集描述的区域中。

        我认为它们对于以下情况特别无用,例如当您拥有大量事务系统且插入非常频繁时,而顺序键是聚集列。你会得到一帮进程都试图在同一个物理位置(“热点”)插入。事实证明,正如在此编辑之前在这里评论的那样,我很遗憾已经过时并且显示了我的年龄。请参阅this post on the topic by Kimberley Tripp,这说明一切要好得多。

        连续数字“ID”列通常不是很好的候选列。名字可以很好,日期也可以——如果仔细考虑的话。

        【讨论】:

        • 如果您相信 Kimberly Tripp,为什么有人不相信她 :-),热点现象在行锁定之前就已经存在。如今,由于缓存,在同一地点进行更新实际上是有益的。
        • 天哪,我怎么过时了?我试图解决这个问题并包含一个链接来纠正它。谢谢!
        猜你喜欢
        • 2012-07-01
        • 2011-10-23
        • 2023-03-19
        • 2021-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多