外键首选字符串还是整数?
Posted
技术标签:
【中文标题】外键首选字符串还是整数?【英文标题】:Is string or int preferred for foreign keys? 【发布时间】:2011-06-16 08:53:36 【问题描述】:我有一个包含 userid
和 username
列的用户表,它们都是唯一的。
在userid
和username
之间,哪个更好用作外键,为什么?
我老板想用字符串,可以吗?
【问题讨论】:
请问为什么表中有两个唯一列? 为什么他不能有两个唯一的列。比如有一个 ID、电子邮件和用户名。它们都可以是独一无二的,不是吗? 我承认。愚蠢的问题。只是想知道这两列是否真的在描述同一件事。 nonnb 很好地回答了这个问题。 @Bill 感谢您的编辑希望改进语法。 @Bill 谢谢你的英语很好。想改进我的。 【参考方案1】:int 会更快索引,可能是也可能不是问题,根据您提供的内容很难说
【讨论】:
【参考方案2】:外键首选字符串还是整数?
视情况而定
在Natural and Surrogate Keys 之间的权衡有很多existing discussions - 您需要决定什么适合您,以及您的组织内的“标准”是什么。
在 OP 的情况下,有一个代理键 (int userId
) 和一个自然键 (char
或 varchar 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 变成十六进制时,它会给您带来多大的麻烦?
【讨论】:
以上是关于外键首选字符串还是整数?的主要内容,如果未能解决你的问题,请参考以下文章
将字符串转换为整数。为啥会出现这个错误?我想将 ID(字符串)更改为 IC(整数)。两者都是数组。顺便说一句,我还是个初学者