【问题标题】:How do I enforce uniqueness against four columns如何对四列强制唯一性
【发布时间】:2014-02-16 09:34:31
【问题描述】:

在 SQL Server 2012 中,我有一个包含四列的“交叉引用”表。四列的组合必须是唯一的。我最初的想法是简单地创建一个包含所有四列的主键,但一些研究表明这可能不是一个好主意。

问题背景... 我正在尝试在旧版 Web 应用程序上实现标记服务。一些需要标记的对象使用唯一标识符作为它们的主键,而另一些则使用简单的整数 id。我已经使用“双表”方法解决了这个问题。一个表包含标签,而另一个表提供要标记的对象和标签表之间的引用。这张表我有名字 TagList...

CREATE TABLE TagList (
    TagId          nvarchar(40)     NOT NULL,
    ReferenceGuid  uniqueidentifier NOT NULL,
    ReferenceId    int              NOT NULL,
    ObjectType     nvarchar(40)     NOT NULL
)

例如,要使用带有单词“example”的 uniqueidentifier 主键标记对象,TagList 记录将如下所示:

TagList (
    TagId          'example',
    ReferenceGuid  '1e93d578-321b-4f86-8b0f-32435d385bd7',
    ReferenceId    0,
    ObjectType     'Customer'
)

要使用带有单词“example”的整数主键标记对象,TagList 记录将如下所示:

TagList (
    TagId          'example',
    ReferenceGuid  '00000000-0000-0000-0000-000000000000',
    ReferenceId    5639,
    ObjectType     'Product'
)

实际上,TagId 和 ReferenceGuid 列必须是唯一的,或者,如果正在定义一个 int 主键对象,则 TagId、ReferenceId 和 ObjectType 必须是唯一的。

为了简化(?)事情,使所有四列的组合是唯一的也将用于相同的功能目的。

任何建议将不胜感激。

【问题讨论】:

  • ObjectType 与参考 guid 和参考 id 有什么关系?让我知道这两列是否存在对象类型的任何功能依赖关系?
  • 在定义方面,在定义具有唯一标识符主键的对象时,对象类型并不是严格必要的。当使用整数主键定义对象时,对象类型将一个 id 与另一个区别开来,例如例如,ID 27 可以指代产品或客户,对象类型定义了哪一个。对象类型也用于标签搜索:查找标签为“示例”的所有客户

标签: sql sql-server tags indexing


【解决方案1】:

拥有多列主键应该可以解决问题

CREATE TABLE TagList (
    TagId          nvarchar(40)     NOT NULL,
    ReferenceGuid  uniqueidentifier NOT NULL,
    ReferenceId    int              NOT NULL,
    ObjectType     nvarchar(40)     NOT NULL,
    CONSTRAINT pk_TagList PRIMARY KEY (TagId,ReferenceGuid,ReferenceId,ObjectType)
)

【讨论】:

  • 嗨 Lee,这是我最初的计划,但是当我对此进行调查时,我发现有几篇帖子表明这种方法出于性能原因并不理想,最好引入代理主键 (例如身份整数),然后添加特定索引来控制 TagId+ReferenceGuid 或 TagId+ReferenceId+ObjectType 的“唯一性”。当然,您的建议似乎更简单。
  • 嗨,对不起,我没有完全阅读您的问题,以这种方式进行约束将强制输入唯一性,因为有一个额外的条目来管理身份将依赖于 ReferenceGuid 和 ReferenceId 被输入为唯一每一次。我认为看看你的结构,你不需要所有四个都在你的约束中只有 ReferenceGuid 和 ReferenceId?我个人也会将 ObjectType 拉出到一个单独的表中,该表链接到 ObjectTypeId 外键上的 TagList。
  • 如果 ReferenceId 是增量的,我建议将它放在主键的开头。如果您不手动设计 CLUSTERED 索引,它将与 PRIMARY KEY 相同。如果 ReferenceId 是增量的,那么每个新行都将存储在表的末尾(实际上是在页面的末尾)。如果 TagId 是第一个并且这是字母数字的无序实体,那么每个新行都将“随机”存储在表格中间(实际上是在页面中间) - 因此可能会出现页面碎片。
  • 多列键可能有一些缺点,例如较长的外键或使某些解决方案无法应用(例如,FULL TEXT SEARCH 需要具有一列主键)。另一方面,多列键可能更具可读性(例如:父 id + 子本地 id + 子本地 id)。
  • 谢谢李,这感觉像是一个更干净的方法
【解决方案2】:

如果您只需要唯一约束,而不需要主键,则可以使用:

ALTER TABLE TagList
ADD CONSTRAINT UK_TagList_1 UNIQUE
(
    TagId,
    ReferenceGuid,
    ReferenceId,
    ObjectType
)

【讨论】:

    【解决方案3】:

    我没有所涉及实体的所有信息,但由于我的能见度有限,我会尝试建议遵循第一剪设计:

    创建两个单独的表,一个带有 TagId 和 ReferenceGuid,另一个带有 TagId 和 ReferenceId。不过,我不确定 ObjectType。如果 ObjectType 不是隐式的,那么这也可以在这两个表中维护。然后可以在这些表的顶部创建一个视图来拍摄可以包含所有必需列的查询。 这样我们就可以解决当前设计中的空间浪费问题。 如果此设计不能解决手头的问题,请提供您的意见。

    【讨论】:

    • 谢谢 Dipendu,这类似于上面建议的最终方法,看起来是一种更简洁/结构更好的方法。
    猜你喜欢
    • 1970-01-01
    • 2021-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-20
    • 2011-02-18
    相关资源
    最近更新 更多