每个 MySQL 表都应该有一个自动递增的主键吗?
Posted
技术标签:
【中文标题】每个 MySQL 表都应该有一个自动递增的主键吗?【英文标题】:Should every MySQL table have an auto-incremented primary key? 【发布时间】:2011-11-12 13:14:06 【问题描述】: 我了解主键的价值。 我了解索引的价值。是否应该每个 mysql 表都有一个自动递增的主键(最好是 INT 字段类型)?
更新
@Raj More 的回答似乎是最有效的。然而,当我想到这个问题时,这个自动递增的主键 ID 将如何与其他表相关联。例如:
表 1
ID | firstname | lastname | email
----------------------------------------
1 | john | doe | 1@email.com
2 | sarah | stow | 2@email.com
3 | mike | bro | 3@email.com
表 2
ID | memberid | display | address
--------------------------------------------
1 | 1 | funtime zone | 123 street
2 | 3 | silly place llc | 944 villa dr
在上面的示例中,消费者可能会来到网站并选择注册免费产品/服务。如果消费者选择,他们可以提供额外的信息(存储在表 2 中)以进行额外的邮寄等。我看到的问题是这些表与“主键自动递增字段”的关系。在表 2 中,“memberid”与表 1 的 ID 相关,但这并不是“非常”清楚的。放入表 2 的任何新信息都将递增 1,但并非所有消费者都会选择参与表 2 所需的数据。
【问题讨论】:
Surrogate vs. natural/business keys的可能重复 @ypercube - 真的吗?您将其列为另一个答案中给出的示例的可能重复项?第一个评论者进行了类似的评估,投了赞成票,然后删除了他自己的评论。 为什么听起来很奇怪? ("完全重复:这个问题与之前关于该主题的问题所涵盖的内容完全相同;它的答案可能会与另一个相同的问题合并。") 我的回答很快就会被删除。我的观点是,这两种选择都有很多优点和缺点(在其他类似问题中讨论过)。说“我喜欢这个,我选择是的,阅读这个”并不是一个真正的答案。 您的更新是表 (2)(与另一个表具有 1:1 关系)的一个很好的例子,其中自动递增的主键是无用的。memberid
可以是 PK(不是自动递增,因为它也是 table1 的 FK)。
【参考方案1】:
我不是代理键的忠实粉丝。我还没有看到我更愿意为数据库的每个表使用一个的场景。
我会说不。
阅读这个答案:surrogate-vs-natural-business-keys
以上内容可能被视为讽刺或煽动性(尽管点赞数出奇地多),因此将其删除。
在一般情况下,有很多关于代理和自然键的问题和答案,所以我觉得这个问题更像是重复。我的观点是代理键很好而且非常有用,主要是因为自然键可以在连接表链的低端导致非常大的主键 - 许多 RDBMS 处理不好,聚集索引变大等. 但是说“每个 MySQL 表都应该有一个自动递增的主键”是一个非常绝对的陈述,我认为在某些情况下他们真的提供很少或根本没有提供。
由于 OP 更新了问题,我将尝试对该特定主题发表评论。
我认为这正是自动递增主键不仅无用而且增加了负值的情况。假设table1
和table2
在1:1
关系中,memberid
可以是Primary Key
和Foreign Key
到table1
。
添加一个自动递增的 id 列会添加一个索引,如果它是一个集群索引(如 InnoDB PK 索引),则会增加 memberid
索引的大小。更重要的是,如果您有这样一个自动递增的 id,则必须使用此 id
(与表 2 的关系 1:n
中的表的 JOIN)和一些使用 memberid
( 1:n
与 table1
关系中的表的 JOIN)。如果你只有 memberid
这两种类型的 JOIN 都可以
使用memberid
完成。
【讨论】:
我预计这可能会因讽刺而被否决,但请注意我没有。我已经通读了几次提供的链接(由上面的 Raj More 提供),并认为它确实具有一些很好的内在价值(因为我是数据库开发的新手,所以有些概念在我脑海中浮现)。我添加了一个更新,您可以提供评论。 您(或者我自己也意识到了,哈哈)在考虑无用数据时实际上提出了一个很好的观点。我可以看到上面表 2 中的 ID 之类的唯一好处只是查看插入内容的时间和顺序(尽管日期也可以完成此操作)。 好吧,那么它不是ID(dentifier)
,而是一个排序。并且有很多情况下,自动生成的ID与插入的顺序不一样(UUID、并发线程、主从数据库等场景)。【参考方案2】:
我是代理键的忠实粉丝。我还没有看到我不想使用的场景。
我会说是的。
阅读这个答案Surrogate vs. natural/business keys
编辑
我将更改我的答案以包括以下内容:
在某些情况下,我现在使用实际值作为代理键:
DimDate (20151031, 20151101, 20151102....)
DimZipCode (10001, 10002, 10003...)
其他所有东西都有代理键。
【讨论】:
每张桌子?例如,带有Code, Name
字段的表Country
最好使用Code CHAR(2) Primary Key
定义。
如果我有一个国家代码的错误数据并且需要在维度中进行更改,那么我将不得不更新我的整个事实表,我的事实索引可能会不同步.另外我宁愿不级联更新
@Raj More - 添加了补充更新,我认为这最终突出了我的问题。在示例中,即使实际信息是相关的,每个表的“自动递增”ID 也会有所不同。随着越来越多的表被添加,“自动递增”的值似乎变得徒劳,只是一个行数。
如果您有不良数据,那么这是您能想到的最好的理由,就是不让他们进入您的数据库。如果有人告诉您他居住在 ISO 代码 XQ 的国家,那么您是认为您的 ISO 代码列表已过时,还是认为该人是骗子?【参考方案3】:
是的,有一个例外:
一个在其他两个表之间实现 n:m 关系的表,一个纯链接表,如果它只有两个字段,则不需要这样的字段,引用链接表的两个主键。链接表的主键则由这两个字段组成。
只要链接表有额外的信息,它就需要一个简单的单字段主键。
话虽如此,可能还有更多的例外;数据库设计是一个非常广泛的领域...
编辑:在上一句中添加了更多。
【讨论】:
如果链接表将在下游的任何进一步关系中使用,现在您拥有更大的 FK(和更大的索引)。考虑减少此类链接表的 3 个关系 - 一组 8 列而不是 3 列的 FK。就个人而言,我宁愿从代理键开始。 @Raj,你是对的;如果链接表将在下游的任何进一步关系中使用,它不再是一个简单的链接表,它也有额外的信息。我同意在这种情况下添加代理键。 那么有一个异常(本身就有异常),可能还有其他异常?! @onedaywhen:是的,类似的。我试图贡献我们的经验法则,我将插入缺少的单词“更多”。顺便说一句,这个主题似乎释放了很多感情:) @onedaywhen - 您投票结束了一个问题,因为答案可能有例外?这很有意义....以上是关于每个 MySQL 表都应该有一个自动递增的主键吗?的主要内容,如果未能解决你的问题,请参考以下文章