【问题标题】:SQL primary key on lookup table or unique constraint?查找表或唯一约束上的 SQL 主键?
【发布时间】:2016-11-30 16:19:02
【问题描述】:

我想创建一个查找表'orderstatus'。即下面,只是为了澄清这将在数据仓库中使用。如果需要,我将需要通过 OrderStatus 加入以检索 INT(如果我创建一个)以在其他地方使用。例如在事实表中,我会将 int 存储在事实表中以链接到查找表。

+------------------------+------------------+
| OrderStatus            | ConnectionStatus |
+------------------------+------------------+
| CLOSED                 | APPROVE          |
+------------------------+------------------+
| COMPLETED              | APPROVE          |
+------------------------+------------------+
| FULFILLED              | APPROVE          |
+------------------------+------------------+
| CANCELLED              | CLOSED           |
+------------------------+------------------+
| DECLINED               | CLOSED           |
+------------------------+------------------+
| AVS_CHECK_SYSTEM_ERROR | CLOSED           |
+------------------------+------------------+

就主键/唯一键而言,最佳做法是什么?我应该创建一个 OrderStatusKey INT 作为具有身份的 PrimaryKey 吗?还是对订单状态创建唯一约束(唯一)?谢谢。

【问题讨论】:

标签: sql sql-server sql-server-2012


【解决方案1】:

为此,我建议您创建一个 Identity 列,并将其设为集群主键。

表具有某种类型的主键被认为是最佳实践,但是像这样的表具有聚集索引是允许在多表查询(使用连接)中使用该表的最快方法。

这是一个关于如何添加它的示例:

ALTER TABLE dbo.orderstatus 
ADD CONSTRAINT PK_orderstatus_OrderStatusID PRIMARY KEY CLUSTERED (OrderStatusID);
GO

文章更详细MSDN

这里是另一个解释主键的资源Primary Key Primer

【讨论】:

  • 我不反对,但你能详细说明为什么吗?
  • 不要混用 PRIMARY KEY 和 CLUSTERED INDEX 的概念。
  • 为什么不创建一个 OrderStatusKey INT 作为主键标识,在 OrderStatus 上使用唯一约束或非聚集索引,或者这是否矫枉过正?什么是性能更高的非聚集索引或唯一约束?
  • 对于这种类型的表,您不需要唯一的约束,这有点矫枉过正。您在这里只需要一个集群的主键。如果您有更复杂的表类型,则可能需要查看唯一约束。
  • 谢谢你澄清了事情。
【解决方案2】:

如果OrderStatus 是唯一的并且主标识符并且您将在相关表中直接重用此状态代码(而不是指向此状态代码的数字指针),则保持列不变并使OrderStatus 成为主要集群指数。

一点解释:

主键在整个表中是唯一的;聚集索引将所有记录数据与该索引联系起来。主键不一定是表上的聚集索引,但通常是这种情况。


如果您要使用状态代码以外的其他内容链接到订单状态,则创建另一个 int 类型的列作为 IDENTITY 并将其设为主集群键。还要向OrderStatus 添加一个唯一的非聚集索引,以确保永远不会添加重复项。


不管怎样,每个表都应该有一个主键和一个聚集索引(同样,它们通常是同一个索引)。

【讨论】:

    【解决方案3】:

    以下是一些需要考虑的事项:

    • PRIMARY KEY 确保表中没有 NULL 值或重复项
    • UNIQUE KEY 可以包含 NULL 和(根据 ANSI 标准)任意数量的 NULLs。 (此行为取决于 SQL Server 设置和可能的索引过滤器 r 非空约束)
    • CLUSTERED INDEX 包含与叶子上的一行相关的所有数据。
      • 当CLUSTERED INDEX 不唯一(且不为空)时,SQL Server 将为每一行添加一个隐藏的GUID。
      • 当键列不唯一时,SQL Server 将隐藏的 GUID 列添加到键列列表中以区分各个记录)
    • 所有索引都使用聚集索引的键列的值或堆表的 rowid。
    • 查询优化器使用索引统计信息找出执行查询的最佳方式
    • 对于小表,索引通常被忽略,因为进行索引扫描,然后查找每个值比进行全表扫描更昂贵(当你有非常小的表时,它将读取一两页)
    • 状态查找表通常非常小,可以存储在一页上。

    引用表将在其结构中存储 PK 值(或唯一值)(这也是您将用来进行连接的内容)。如果您有一个整数键用作参考(在 SQL Server 中也称为 IDENTITY),那么您可以获得轻微的性能优势。

    如果您通常不想列出 ConnectionStatus,那么使用实际显示值 (OrderStatus) 可能会有所帮助,因为您不必加入查找表。

    您可以将这两个值都存储在引用表中,但是维护这两个列会产生一些开销和更多的错误空间。

    集群/非集群问题取决于此表的用例。如果您通常使用OrderStatus 进行过滤(使用文本形式),则OrderStatus 上的NON CLUSTERED IDENTITY PK 和CLUESTERED UNIQUE 可能会有所帮助。但是(正如您在上面看到的那样),在小表中,效果/性能增益通常可以忽略不计。

    如果你不熟悉上面的东西,觉得更安全,那就在OrderStatus上创建一个身份集群PK(OrderKey或OrderID)和一个唯一的非集群密钥。

    使用 PK 作为外键中的引用/引用列。

    还有一件事:如果该列仅被一个表引用,您可能需要考虑创建一个包含两个表数据的索引视图。

    另外,如果没有设置状态,我建议添加一个您可以使用的虚拟值(并将其用作所有引用列的默认值)。因为未设置仍然是一种状态,不是吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-22
      相关资源
      最近更新 更多