案例 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 之类的一些代理可能是随机排序的。