Mysql 数据库需不需要主键 Id?

2020-03-19 10:20:04 +08:00
 wangbenjun5

最近接触了一个项目,里面的数据库设计让我“大开眼界”,很多表没有主键 id,取而代之的是复合主键,也就是几个字段同时作为主键,比如说: A 表:

name
age
addr

主键是 name+age

B 表:

name
age
money
something
xxx

主键也是 name+age

实际上 B 表是 A 表的附属表,也就说是补充 A 表的内容,或者是关联到其它表

恕我愚昧,不知道这种设计有什么好处,我觉得用 id 当主键更简介方便,便于修改数据,比如上面的例子有时候还有修改 age 的需求,这时候就非常麻烦了,难道这是反范式化设计,故意做的数据冗余,我不敢苟同,咱也不敢问,咱也不敢说。

各位大佬,求打醒!!!

13545 次点击
所在节点    MySQL
99 条回复
jswh
2020-03-19 13:57:24 +08:00
逻辑上没问题,表小当然可以这么玩。自增主键的好处是插入的时候是顺序的。
yjxjn
2020-03-19 14:15:26 +08:00
@assad 其实楼主举的例子不恰当,之前做过的项目,一些关联表,确实没有主键,确实拿的就是两个字段合并做一个的,业务表里面,我见过,比如省份名字, province_name,city_name,postcode,各种关联, 确实没有主键,还有一种就是设计工资等级,比如 1W-2W 是 A 级别,2-3WB 级,这样的。。。当时做项目好奇,但是还是不建议这么做,检索的时候,性能那叫一个垃圾。
littlewing
2020-03-19 14:21:17 +08:00
@fancy111 31 楼的 tant 已经解释的非常清楚了,你可以参考
Lonely
2020-03-19 14:31:42 +08:00
@passerbytiny 你也别出来回复了,徒让人笑话。
arry
2020-03-19 14:53:51 +08:00
@passerbytiny innodb 在插入数据的时候本身就是有序的,所以才需要创建一个自增 id,否则每次新增一个记录都需要做移动数据,页分裂等操作,缓存空间中的数据也需要频繁更新。
Atsushi
2020-03-19 14:56:20 +08:00
@loading 哈哈,我就干过数据库加 age,还有出生年月也在。而且身份证号码还能重复。
反正产品发话了,我就不管了
iConnect
2020-03-19 14:57:03 +08:00
联合主键一般是别的表的主键联合起来用,不是你上面的这个场景
v2Geeker
2020-03-19 15:01:32 +08:00
没有主键 mysql 内部也会给你创建一个~
passerbytiny
2020-03-19 15:19:13 +08:00
@tabris17 #50 @Lonely #56 两位这是做过什么事,@我是没提醒的。

至于 tabris17 你的回复,你的目光局限到了 InnoDB 引擎上面。热点问题那可不是极端情况,在大数据存储上可是首要问题,关系数据库上热点问题仍然存在,只不过数据量小的时候无需关注罢了,数据量一大照样得使用表分区来避免热点。InnoDB 引擎下若真因为非顺序主键拆分页造成性能灾难,那主因是 InnoDB 引擎而不是顺序主键,难不成 InnoDB 引擎要告诉所有人“我太娇贵,那些用 UUID 当主键的我伺候不了”。

正好又来了 @arry 的新通知,那就一并回复了,性能跟业务逻辑之间,是要做取舍的,不能为了微小的性能提升而牺牲过多业务逻辑的简洁性。现在 InnoDB 要求顺序主键,业务上需要自增主键来自动生成主键,二者正好相互支持。但如果哪天业务上需要把主键换成 UUID 了,要么 InnoDB 引擎能保证性能损失不大,要么就要换掉 Mysql 了。

需要说明一点,本人不是数据库开发者,或者表面是 Java 本质是 SQL 开发的程序员,我推崇的是用 JPA/Hibernate 完全隐藏掉任何数据库细节,并且在主键选择上倾向于 UUID 和自然主键。
wmhx
2020-03-19 15:45:33 +08:00
很多表比如就用身份证来做主键了, 手机号码了, 也不一定非要多一个 ID 啊, 理解了, 做表关联还是非常方便的, 否则 FID 多了, 真不容易记住.
saulshao
2020-03-19 15:45:41 +08:00
我倾向于有 ID 主键的原因主要是基于实践。其实如果一个人能预测未来,那从逻辑上看有没有 ID 主键根本无所谓。
但是问题在于没人能预测未来,今天你建了一个表以 name+出生地来标识一个确定的人,明天可能就需要根据这个表来扩展出一堆的表来存储别的什么东西。要是万一前面那个表需要改成 Name+出生地+出生日期才能标识一个确定的人。
我实在就想不出来到底该怎么处理后面那堆派生出来的表了.......
wangkun025
2020-03-19 15:49:02 +08:00
性能冗余的话,只要不出错就行。
ocean1477
2020-03-19 15:52:49 +08:00
官方推荐需要有自增主键,数据紧凑,页分裂操作少。
arry
2020-03-19 15:54:14 +08:00
@passerbytiny 用自增主键并不需要牺牲多少业务简洁性,至少在我见过的代码中,直接显式使用主键来进行业务操作的非常少。所以几乎不存在业务上把自增主键改成 uuid 这种情况,反而是自然主键这种和业务强关联的字段,会因为业务的变更而产生重复 冲突的情况。
而使用 uuid 这种情况就更不能理解了,使用 uuid 必然会使得效率降低,而且占用更多的空间。
passerbytiny
2020-03-19 16:17:32 +08:00
@arry #66 你别告诉我你们系统中基本没有 findById、editById、deleteById 之类的方法。业务变更必然要修改代码,有冲突解决就行了,为了避免将来可能有的冲突而现在不用自然主键,这属于超前设计,现在敏捷开发盛行,已经不受推崇了。你大概没做过更换系统时候的数据割接,那时候只有 UUID 主键是不会冲突的,自增主键和自然主键都会冲突(但是,若提前将主键定位 UUID 也是超前设计,不推荐)。

我推崇 UUID 的原因是它是最省事的主键。自增主键或序列主键都依赖数据库,同时,相比于有顺序有意义的数值,毫无顺序毫无意义的 UUID 才更像 ID。最后那一句就不回了,前面已经说得很清楚了。

顺便提一下,抛开数据库往外面看,git、docker 都是用 UUID 当主键的。
reedthink
2020-03-19 16:38:56 +08:00
主键必须和数据无关,这不是常识吗=。=
竟然还有人这样写,服了
killerv
2020-03-19 16:56:28 +08:00
#76 楼上的建议很正确,主键必须和业务无关。而且如果不是百分之百确定不需要主键,那就加上。
cobola
2020-03-19 18:28:42 +08:00
我喜欢 shortid uuid 太长 不舒服
qq1004108488
2020-03-19 18:34:20 +08:00
@passerbytiny 我却是觉得用 user_id 真的是设计有问题,你的表名已经指定是的 user 表,然后 id 还要叫 user_id,这是很多余的写法。
fox0001
2020-03-19 19:15:10 +08:00
复合主键,数据更新后,重建索引是噩梦

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/654133

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX