我可以使用VARCHAR作为主键吗?

83

我有一个用于存储优惠券/折扣的表格,我希望使用coupon_code列作为主键,它是一个 VARCHAR 类型。

我的理由是每个优惠券都将有一个唯一的代码,并且我将运行的唯一命令是 SELECT ... FROM ... WHERE coupon_code='..'

我不会做任何连接或索引操作,我认为在这个表中不会有超过几百条记录。

在我看来,这样做应该是可以的,但我不知道是否有任何我遗漏或没有考虑到的问题。


8
好的,我会尽力为您提供准确且易于理解的翻译。以下是需要翻译的内容:是的(还需要12个……) - Rufinus
2
禁不住想,这很容易测试。 - Neil Knight
1
通常情况下,主键用于唯一标识一个表,以便您可以轻松地将其链接到另一个表。我建议将该字段设置为UNIQUE。 - Linger
6
你不打算加入这个计划了吗?没有人想知道谁使用了这些优惠券,使用了多少次,或者用于什么商品? - Meff
4个回答

143
当然可以,在您的关系型数据库管理系统允许的情况下。不过,是否应该这样做的答案是不同的:在大多数情况下,具有超出数据库系统范围意义的值不应被选择为主键。
如果您知道该值在您所建模的系统中是唯一的,则适当地向表格添加唯一索引或唯一约束条件。但是,通常情况下,您的主键应该是某些“无意义”的值,例如自动递增的数字或GUID。
这样做的理由很简单:数据输入错误和似乎不可更改的事物的变化确实会发生。它们变得更难以修复用作主键的值。

我不知道。我认为你不应更改独特标识数据的方式。假设你通过社保号码来唯一标识雇员(绝对不行),你会更改雇员的社保号码吗? - terary
6
作为翻译,我的任务是让原文更通俗易懂而不改变其意思。原文中提到用户和数据库如何唯一标识数据是有区别的。在数据库中,使用主键来唯一标识数据,但并非所有唯一字段都必须是主键。例如,社会安全号码(SSN)可以作为一个独特的字段而不是主键。这样做可以在需要时更改SSN,比如发现输入错误时。 - Sergey Kalinichenko
@dasblinkenlight,我理解你的观点,但我不确定是否同意。如果存在数据输入错误,DE职员会颠倒SSN。该错误在几个月内未被发现,文件被提交给政府和其他人,然后才被检测到---这个值应该更改吗?在这种情况下,使用主要的“约束”是安全的。原始记录应保持完好无损,做出注释,并创建一个新用户。从而创建一个准确的逻辑纸质跟踪。 - terary
3
这里的观点是错误的。我认为,在许多情况下,拥有有意义的主键或组合主键是有优势的。 - Jiulin Teng
嗯,我也不确定我是否同意。使用自然键还是代理键似乎非常具体情况而定,没有一种适用于所有情况的方法。 - html_programmer
显示剩余3条评论

25

一概而论"不应该这样做"是可怕的建议。根据您的用例、工作负载、数据熵、硬件等情况,在许多情况下这是完全合理的。您不应该做出假设。

需要注意的是,您可以指定一个前缀来限制MySQL的索引,从而在扫描其余部分之前有所帮助,缩小结果范围。然而,随着前缀的“填满”和变得不太唯一,这可能会变得越来越不实用。

这很简单,例如:

CREATE TABLE IF NOT EXISTS `foo` (
  `id` varchar(128),
  PRIMARY KEY (`id`(4))
)

还要注意,前缀(4)出现在列引用后面。其中4表示应该使用128个可能字符中的前4个字符作为id

最后,在使用索引前缀之前,您应该先了解它们的工作原理和限制: https://dev.mysql.com/doc/refman/8.0/en/create-index.html


请注意,NDB集群不支持索引前缀 https://dev.mysql.com/doc/refman/8.0/en/mysql-cluster-limitations-unsupported.html - jchook
1
省略“前缀(4)”,默认使用128吗? - pmiguelpinto90

2

这取决于具体的使用情况。

如果您的表是静态的,并且只有短列表的值(并且在数据库的生命周期内几乎不可能更改),我建议使用以下结构:

CREATE TABLE Foo 
(
    FooCode VARCHAR(16), -- short code or shortcut, but with some meaning.
    Name NVARCHAR(128), -- full name of entity, can be used as fallback in case when your localization for some language doesn't exist
    LocalizationCode AS ('Foo.' + FooCode) -- This could be a code for your localization table... 
)

当你的表不是静态的时候,使用INT作为主键是最好的解决方案。

0

没问题,只有几百条记录的话速度会很快。

你可以添加一个唯一的id作为主键(int自增),并将coupon_code设置为唯一。因此,如果您需要在其他表中进行请求,最好使用int而不是varchar。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接