使用具有标称值的单个列表作为PK是不好的做法吗?

时间:2017-03-25 15:39:52

标签: sql sql-server

在处理No-SQL数据库时,这不会是一个问题,因为关系没有意义(或者至少不需要),但是当基础结构不支持No-SQL数据库时,创建标记等场景对于文章会引起一些担忧(从找到最佳实践的角度来看)。

假设我有三个表ArticlesTagsArticleTags。在这种情况下,Tag名称必须是唯一的,因为Tags表中的重复标记没有任何意义。将此记入帐户,我可以执行以下操作:

CREATE TABLE [Tags](
     [TagId] UNIQUEIDENTIFIER ROWGRIDCOL PRIMARY KEY DEFAULT NEWSEQUENTIALID(),
     [Name] NVARCHAR(50) NOT NULL UNIQUE
)

这种方法可以被视为一种标准做法。但是,由于Tags.Name是唯一的,我还可以使用Name列作为主键并删除TagId列。问题是,如果我这样做并使用Tags.Name作为主键,即使Tags表也会被视为冗余,我只需添加一个新列,例如TagArticleTags表中没有任何关系,如果我们想要允许用户在必要时生成新标签(丢失FK约束),这将是可以的。

但是,这会违反规范化规则吗?与标准方法(具有id和名称)相比,这是一种更好的做法吗?

1 个答案:

答案 0 :(得分:2)

将GUID作为主要(可能有例外)是一个相当糟糕的主意。如果你有一个表,你将要进行频繁的插入,那么GUID作为主键肯定是个坏主意。

为什么呢?好吧,默认情况下,主键是在SQL Server中集群的。你可以覆盖它,但让我们坚持默认。

由于GUID可以具有较小的值,因此会导致在现有行之间进行插入。这往往会造成碎片和(很多)较慢的插入。

请注意,这甚至发生在NEWSEQUENTIALID()。正如documentation所解释的那样:

  

重新启动Windows后,GUID可以从较低范围重新开始,   但仍然是全球唯一的。

如果你一次性完成所有插入,那么无关紧要。

然而,这似乎更简单:

CREATE TABLE [Tags](
     [TagId] int identity(1, 1) primary key,
     [Name] NVARCHAR(50) NOT NULL UNIQUE
);

以下是一些原因:

  • 标识列占用的空间较少(整数小于GUID)。
  • 标识列对于引用表非常方便(外键占用的空间更少)。
  • 当查看数据或输入id时(例如调试),人们更容易识别整数ID。
  • 插入内容始终位于表格末尾。

我会避免使用GUID(或其他数据库中的UUID)作为主键的习惯。我不得不放松的一个例子是我使用SparkSQL或BigQuery生成数据。但是,我认为这些工具中的错误是他们无法在大型数据集上轻松row_number()

至于使用Name,我会劝阻。您可能希望在将来的某个时刻重命名标记,或者确定50个字符不够大。虽然你可以有级联外键引用,但我认为一个唯一的整数id是一种更安全的方法。此外,id会提供一些无意的信息 - 例如插入表中的最后一个标记。