外键是首选字符串还是int?

XMe*_*Men 11 mysql sql ddl foreign-keys

我有一个带有useridusername列的用户表,两者都是唯一的.

介于userid和之间username,哪个更好用作外键?为什么?
我的老板想要使用字符串,那可以吗?

Stu*_*tLC 27

看起来你有一个代理键(int userId)和一个自然键(charvarchar username).这两列都可以用作表的主键,无论哪种方式,您仍然可以强制执行另一个键的唯一性.

现在有很多关于自然和代理键之间权衡的讨论 - 你需要决定什么对你有用,以及你组织内的'标准'是什么.

选择这种或那种方式时需要考虑以下几点:

使用代理键的情况(例如UserId INT AUTO_INCREMENT)

如果使用代理(例如UserId INT AUTO_INCREMENT)作为主键,则引用表的所有表MyUsers应该UserId用作外键.

但是,您仍然可以username通过使用其他唯一索引来强制执行列的唯一性,例如:

CREATE TABLE `MyUsers` (
  `userId` int NOT NULL AUTO_INCREMENT,
  `username` varchar(100) NOT NULL,
  ... other columns
  PRIMARY KEY(`userId`),
  UNIQUE KEY UQ_UserName (`username`)
Run Code Online (Sandbox Code Playgroud)

根据@Dagon,使用窄主键(如a int)比使用更宽(和可变长度)的值具有性能和存储优势varchar.这种好处也影响了更多的参考表MyUsers,作为userid缩小的外键.

代理整数键的另一个好处是可以轻松更改用户名而不影响表引用MyUsers.如果将username其用作自然键,则将表连接到MyUsersvia username,这使得更改用户名更加不方便(因为否则会违反外键关系).如果在使用username外键的表上需要更新用户名,则需要使用ON UPDATE CASCADE等技术来保持数据完整性.

使用自然键的情况(即用户名)

在使用代理键的不利方面,通过代理键引用的其他表MyUsers将始终需要join返回MyUsers表以检索用户名.Natural键的一个潜在好处是,如果查询只需要Username表引用的列MyUsers,则它不需要联接回来MyUsers检索用户名,这将节省一些开销.

关于自然与替代辩论的进一步参考以及此处此处的权衡

  • +1是一个务实的答案,两种解决方案各有利弊。就个人而言,我更喜欢替代密钥解决方案。 (2认同)

The*_*heQ 5

一个 int 是 4 个字节,一个 string 可以有任意多个字节。因此,int 总是会表现得更好。当然,除非您坚持使用长度小于 4 个字符的用户名:)

此外,如果列中的数据本身可以更改,则永远不应该将列用作 PK/FK。用户倾向于更改他们的用户名,即使您的应用程序中目前不存在该功能,也许几年后就会出现。当那一天到来时,您可能有 1000 个表引用该用户表,然后您必须更新事务中的所有 1000 个表,这很糟糕。

  • 外键的“更新级联”属性不是可以处理这种情况吗?或者我错过了什么?我确实同意 4 个字节/ 4 个字符的观点。但我不同意第二种说法。 (2认同)
  • 当然,你可以这样做,但这仍然很糟糕。该更新可能会花费更多时间并创建比可接受的更多的锁。但如果这对于特定应用程序来说不是问题,那么就继续吧。但我仍然不推荐它。 (2认同)