2

当将存储在表中的一组值具有在系统中应该是唯一的名称或代码时,是否应该使用 ID 自动增量 (int) 的主键创建它?

以国家缩写的情况为例。除了一致性之外,除了州名或缩写之外,作为主键的表上的 ID 的目的是什么?

例如,如果来自送货地址的外键引用了不可变的州缩写,那么......是否有一个自动递增 int ID 的目的?

4

3 回答 3

2

您强调了单独表格的一个积极方面:一致性。拥有这个要容易得多:

CREATE TABLE dbo.States
(
  StateID TINYINT PRIMARY KEY,
  Name VARCHAR(32),
  Abbreviation CHAR(2)
);

CREATE TABLE dbo.CustomerAddresses
(
  AddressID INT PRIMARY KEY,
  ...,
  StateID TINYINT NOT NULL FOREIGN KEY REFERENCES dbo.States(StateID)
);

比有一个触发器或检查约束,如:

CHECK StateAbbreviation IN ('AL', 'AK', /* 50+ more states/territories... */)

现在,对于像 2 字符状态缩写这样的静态和小的东西,这种设计可能更有意义,消除了缩写和一些代理 ID 之间的一些不必要的映射:

CREATE TABLE dbo.States
(
  Abbreviation CHAR(2) PRIMARY KEY,
  Name VARCHAR(32)
);

CREATE TABLE dbo.CustomerAddresses
(
  AddressID INT PRIMARY KEY,
  ...,
  StateAbbreviation CHAR(2) FOREIGN KEY REFERENCES dbo.States(Abbreviation)
);

这将数据限制为已知的状态集,允许您将实际数据存储在表中(这可以消除查询中的大量连接),实际上为您节省了一些空间,并避免了任何杂乱的硬编码检查约束(或使用 UDF 的约束,或验证数据的触发器)。

总而言之,没有一个神奇的答案可以满足所有设计。随着字符串变大,使用整数而不是仅仅存储字符串会更有意义。一个反例是存储您的网络日志中的所有用户代理字符串 - 存储一次相同的字符串并为其分配一个整数比一遍又一遍地存储相同的 255 个字符的字符串更有意义再次。

其他可能使这个设计麻烦的事情:

  • 如果你以后扩展到美国以外呢?
  • 暂时忘记州的缩写(这是相当静态的);如果您的查找是经常变化的事情怎么办
于 2013-09-26T21:10:11.340 回答
2

作为一般规则(可能不适用于每种情况),出于性能原因,最好使用整数作为主键。因此,如果您的唯一键是字符串,请创建一个自动增量主键。

此外,状态不一定是唯一的。在一个国家确实如此,但是当您查看世界上所有国家/地区时,可能会出现相同的缩写。

编辑

我找不到字符串与整数性能的非常好的证据,但请看一下这里:Strings as Primary Keys in SQL Database

话虽如此,从来没有很多状态,所以在这种情况下性能提升会很小。

于 2013-09-26T20:54:31.940 回答
2

状态缩写是一个很好的非增量主键的罕见示例,原因如下:

  • 它们很小(2 个字符)
  • 他们不会改变
  • 这组值是相对静态的 - 不太可能出现新记录

仅仅因为自然键是唯一的并不能使它成为主键的良好候选者。

即使是真实世界中独一无二的值(如 SSN) ,如果它们是由人类输入的,它们也可能是不错的候选值。例如,假设有人为一个人输入了一堆相关数据,然后收到一封 SSN 错误的信件——现在你不能只更新主键——你还需要更新所有外键!

于 2013-09-26T20:59:14.917 回答