外键首选字符串还是整数?

Posted

技术标签:

【中文标题】外键首选字符串还是整数?【英文标题】:Is string or int preferred for foreign keys? 【发布时间】:2011-06-16 08:53:36 【问题描述】:

我有一个包含 useridusername 列的用户表,它们都是唯一的。

useridusername 之间,哪个更好用作外键,为什么? 我老板想用字符串,可以吗?

【问题讨论】:

请问为什么表中有两个唯一列? 为什么他不能有两个唯一的列。比如有一个 ID、电子邮件和用户名。它们都可以是独一无二的,不是吗? 我承认。愚蠢的问题。只是想知道这两列是否真的在描述同一件事。 nonnb 很好地回答了这个问题。 @Bill 感谢您的编辑希望改进语法。 @Bill 谢谢你的英语很好。想改进我的。 【参考方案1】:

int 会更快索引,可能是也可能不是问题,根据您提供的内容很难说

【讨论】:

【参考方案2】:

外键首选字符串还是整数?

视情况而定

在Natural and Surrogate Keys 之间的权衡有很多existing discussions - 您需要决定什么适合您,以及您的组织内的“标准”是什么。

在 OP 的情况下,有一个代理键 (int userId) 和一个自然键 (charvarchar username)。任一列都可以用作表的主键,无论哪种方式,您仍然可以强制另一个键的唯一性。

以下是选择一种或另一种方式时的一些注意事项:

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

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

但是,您仍然可以通过使用额外的 unique index 来强制 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`)

根据@Dagon,使用窄主键(如int)比使用更宽(和可变长度)的值(如varchar)具有性能和存储优势。这一好处还会影响引用MyUsers 的更多表,因为userid 的外键会更窄(要获取的字节更少)。

代理整数键的另一个好处是可以轻松更改用户名,而不会影响引用MyUsers 的表。 如果username 被用作自然键,而其他表通过username 耦合到MyUsers,则更改用户名非常不方便(因为否则会违反外键关系)。如果需要在使用 username 作为外键的表上更新用户名,则需要像 ON UPDATE CASCADE 这样的技术来保持数据完整性。

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

使用代理键的一个缺点是,如果需要Username 列,则通过代理键引用MyUsers 的其他表将需要JOIN 回到MyUsers 表。自然键的潜在好处之一是,如果查询只需要引用 MyUsers 的表中的 Username 列,则它不需要连接回 MyUsers 来检索用户名,这将节省一些 I/ O 开销。

【讨论】:

+1 以获得务实的答案,这两种解决方案都有其优点和缺点。就个人而言,我更喜欢代理键解决方案。【参考方案3】:

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

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

【讨论】:

外键的“更新级联”属性不是用来处理这种情况吗?还是我错过了什么?我同意 4 个字节/4 个字符的观点。但我不同意第二个论点。 当然,您可以这样做,但仍然很糟糕。该更新可能会花费更多时间并创建比可接受的更多锁。但是,如果这对特定应用程序来说不是问题,请继续。不过我还是不推荐。【参考方案4】:

这取决于外键:如果您的公司可以控制它,那么如果有 ID 字段,我建议使用 Int。但是,有时 ID 字段不在表中,因为另一个键可以作为备用唯一键。因此,在这种情况下,ID 字段可能是代理键。

经验法则:外键数据类型应与主键数据类型匹配。

这里有一个例外:不属于您公司的外键怎么办?您无法控制的数据库和 API 的外键呢?这些 ID 应始终为字符串 IMO。

为了说服你,我问了这些问题:

你在做数学吗?你在增加它吗?你有控制权吗? API 因更改而臭名昭著,甚至可以在其他人的数据库中更改数据类型……那么,当 int ID 变成十六进制时,它会给您带来多大的麻烦?

【讨论】:

以上是关于外键首选字符串还是整数?的主要内容,如果未能解决你的问题,请参考以下文章

数据库 - 字符串作为主键? [复制]

如何检查字符串是浮点数还是整数?

char是整数还是字符?

数据库基础外键什么的

将字符串转换为整数。为啥会出现这个错误?我想将 ID(字符串)更改为 IC(整数)。两者都是数组。顺便说一句,我还是个初学者

如何检查键值是字符串还是整数(ios,Android)