1

我经常看到一些这样的数据库设计:

情况1:

用户表

--id[自动增加]

- 用户名

- 密码

- 电子邮件

案例二:

用户表

- 用户名

- 密码

- 电子邮件

角色表:

--角色ID

--角色名

用户表角色:

--id[自动增加]

- 用户名

--角色ID

我有以下问题:

在案例 1 中:为什么不使用UserName字段作为主键(PK)?为什么使用另一个文件喜欢id [自动增加] 作为 PK?如果只有UserNameEmail,为什么不使用 Email 作为PK呢?那么,最好的方法是什么?

案例2:在UserRoleTable中,为什么不同时使用UserNameRoleID作为PK呢?为什么使用另一个文件喜欢id [自动增加] 作为PK?那么,在这种情况下,最好的方法是什么?

4

4 回答 4

4

案例 1:为什么不使用 UserName 字段作为主键(PK)?为什么使用另一个文件喜欢 id [自动增加] 作为 PK?

UserTable.UserName此数据模型中具有内在含义,称为“自然键”UserTable.id另一方面, 是“代理键”

如果你的模型中有一个自然键,你不能用代理键消除它,你可以替换它。所以问题是:你只使用自然键,还是使用自然键代理键?这两种策略实际上都是有效的,并且各有利弊。

使用代理键的典型原因:

  • 为了使子表中的 FK更小(在这种情况下为整数与字符串),以实现更小的存储和更好的缓存。
  • 避免需要 ON UPDATE CASCADE。
  • 对 ORM 工具的友好性。

另一方面:

  • 您现在有两个键而不是一个,需要一个额外的索引,使父表更大且对缓存不太友好,并且由于索引维护而减慢了 INSERT/UPDATE//DELETE。1
  • 可能需要更多 JOIN-ing 2
  • 并且可能无法很好地使用集群3

如果只有 UserName 和 Email,为什么不使用 Email 作为 PK?

设计者可能希望避免在用户更改电子邮件时需要的 ON CASCADE UPDATE。

案例2:在UserRoleTable中,为什么不同时使用UserName和RoleID作为PK呢?

如果同一用户/角色对不能有多个连接,则无论如何您都必须拥有一个密钥。

除非有 FK 引用的子表UserTableRole或使用了不友好的 ORM,否则没有理由需要额外的代理 PK。


1如果使用集群,自然键下的二级索引可能会额外“胖”(因为它包含集群键的副本,通常是PK)并且在查询时需要双重查找(因为聚集表中的行没有稳定的物理位置,因此必须通过集群键定位,除非一些 DBMS 特定的优化,如 Oracle 的“rowid 猜测”)。

2例如,您无法UserName仅通过阅读联结表找到 - 您必须将其与UserTable.

3代理通常以对客户端应用程序没有意义的方式排序。自动增量代理键的顺序取决于 INSERT 的顺序,并且查询通常不会在“按插入顺序的用户范围”上进行。诸如 GUID 之类的一些代理可能是随机排序的。

于 2012-12-20T03:28:11.070 回答
0

我能想到的不使用像 UserName 这样的东西作为主键的原因之一是它们可能会发生变化。将任何暴露给外界的东西作为主键都会冒着改变这些东西的风险,最好有一个稳定的主键。

如果用户更改了电子邮件或用户名怎么办?你真的想改变你所有关系中的钥匙吗?IMO,最好有一个永远不会看到外界的稳定密钥,每个人都对此一无所知,因此无论数据库中可能发生什么变化,它都可以保持稳定。

于 2012-12-20T02:22:46.980 回答
0

您的问题本质上是使用natural vs surrogate key的优缺点。

灵活性是首要考虑的问题,使用代理键可以更轻松地更改其用户名。将来您可能需要允许重复的用户名,例如合并。

速度是另一个问题,在像用户表这样经常访问的表上,对整数进行连接通常比对字符串进行连接要快。

另一个是表大小,当用作外键时,您必须存储整个键的值。代理非常紧凑,比自然键小得多。

大多数 ORM 还需要使用代理,因为它提供了表之间的一致性。

此外,在许多系统上,假设电子邮件是唯一的可能不一定安全。

我同意在像 UserRole 这样的关系表中,通常最好使用外键中的主复合键。

于 2012-12-20T02:45:13.040 回答
0

在您的示例中,我可以想到在用户名上使用代理主键 (Id) 的几个原因。

  1. 如果有的话,id 字段很少会受到更新。如果用户名是主键,您必须在更新时级联到使用用户名作为外键的所有表。
  2. 表现。int 比较优于字符串比较。
  3. id 键在其他表中作为外键时会占用更少的存储空间。
  4. id 字段允许您不公开敏感数据。例如,考虑一个网络应用程序 url domain/posts/user/1242 vs domain/posts/user/myusername

对于您的第二个问题,使用 userid 比使用 UserTableRole 中的用户名更好。对于这个多对多表是否也包含一个代理键是否更好,这是一个见仁见智的问题。我讨厌对多对多表使用代理 id 键,并且通常只制作两个外键 id 的复合主键。我会在这里考虑代理键的唯一一次是如果我需要在另一个表中将它用作外键。

于 2012-12-20T02:56:59.227 回答