比如:
用户表中,将用户邮箱+密码的值去做 MD5,得出来的值作为 userId
订单表中,将订单数据+时间戳的值去做 MD5,得出来的值作为订单 Id
主要的疑问是,32 位的 id 是否过于占用空间?
以及其他缺点希望各位 V 友能发表下看法。
1
Takamine 2020-05-05 15:16:24 +08:00 via Android
……这样做的意义是什么,强行想让主键 id 和业务含义关联起来吗。
|
2
ajaxfunction 2020-05-05 15:18:04 +08:00
要是用户密码改了呢? 之前生成的 userid 和现在的 userid 不一样,系统不就乱了吗?
简单的问题复杂化了啊! |
3
creedowl 2020-05-05 15:18:32 +08:00 via Android
要是用户改密码怎么办,如果是想要隐藏真实 id 可以用 hashid
订单可以用雪花算法 |
5
nvkou 2020-05-05 15:21:27 +08:00 via Android
uuid 也是这么做的。只不过人家用一去不回头的时间做种子之一。
没有必要重复发明轮子 |
6
kerb15 OP |
7
luopengfei14 2020-05-05 15:23:18 +08:00
用户一旦修改邮箱、密码,你就找不回来 userId,而且 md5 生成的 userId 对索引不友好。
简单点直接用自增 id 当作 userId,考虑多的可以用雪花算法生成 userId,一般够用。 还有 md5 、uuid 字符串理论上避免不了重复的可能 |
8
yukiloh 2020-05-05 15:23:30 +08:00
用户登陆用账号行不,手机行不,你要做 3 个 userid 吗
|
10
chendy 2020-05-05 15:26:18 +08:00
负载不大自增就够用了
至于 “32 位过于占用空间?”…emm ??? |
11
kerb15 OP 好吧,我的表达存在歧义,其实这个 userid 并不作为对外公开的值,也不提供给用户登录使用,只是内部对用户的一个标识,可以理解为就是用户表的主键 id
|
12
murmur 2020-05-05 15:28:12 +08:00
uuid 也比 md5 好啊,你的用户量多少,少的话可以,多的话得考虑下防装,你估计是看了 mongo 那个主键,别人是有算法的,可以保证在数据结构上的一些优化
|
16
changePro 2020-05-05 15:34:09 +08:00 via Android
“md5 生成的 userId 对索引不友好” 少误导其他人
|
17
wangyzj 2020-05-05 15:36:17 +08:00
不是不行, 百害无一利
|
18
changePro 2020-05-05 15:37:34 +08:00 via Android
首先,为什么要这样做?主键 ID 几乎都是 fixed length,磁盘内存、又便宜,索引不是问题。md5 也可以看作是 UUID,用 UUID 做主键大部分是为了解决分布式的一些问题,题主是为了折腾?
|
19
Jacky23333 2020-05-05 15:39:59 +08:00 via Android 3
你这样做会严重影响插入性能,因为会频繁导致页分裂跟行移动,产生空间碎片
|
20
Jacky23333 2020-05-05 15:41:26 +08:00 via Android 1
@changePro 我觉得没毛病啊
|
21
msg7086 2020-05-05 15:52:31 +08:00 via Android
主键不与业务相关。你看看你的想法是否违反了这条惯例。
|
22
xuanbg 2020-05-05 15:55:41 +08:00
占空间倒没什么,现在存储这么便宜……
问题是: 1 、效率低,算一个哈希值也是有开销的。 2 、建立索引效率受影响。 然后,直接用 uuid 他不香吗? |
23
changePro 2020-05-05 16:32:24 +08:00
@Jacky23333 会导致性能下降,如果缓存不命中,导致大量磁盘 IO 。因为相同的数据,page 更多了。buffer pool 设计好的话的话,其实也还好
|
24
PopRain 2020-05-05 16:34:06 +08:00
如果不想用 uuid, 推荐 Twitter 雪花(SnowFlake)算法,一个 64 位整数
|
25
l3n641 2020-05-05 16:53:23 +08:00
不建议这样做,主键越长 索引也占用空间.如果数据量大的话,添加和更新数据会很大影响性能.如果是 mysql 的 inodb 的话.其他的普通索引都会包含主键键值.这时候会更加占用空间.
|
26
saulshao 2020-05-05 17:06:15 +08:00
通常情况下,主键字段就选择单纯的整数 /大整数 /无符号整数就行。
凡是需要某种业务相关计算来"产生"主键值的动作,都是花费很高并且没什么收益的方案。 |
27
yinzhili 2020-05-05 17:11:28 +08:00
不建议。这样的订单号过长,且可读性几乎等于 0 。
|
28
PHPer233 2020-05-05 17:33:08 +08:00 via Android
一个简单的 id 让你搞得这么复杂
|
29
yjxjn 2020-05-05 17:38:25 +08:00
雪花算法不香么?
|
31
joooooker21 2020-05-05 18:09:55 +08:00
单体应用可以用自增主键
分布式应用可以用雪花算法或 uuid 你说的这种方法没有意义且消耗资源 |
32
xiangyuecn 2020-05-05 18:16:39 +08:00
设计 ID 结构最核心的一点,我觉得应当是时间粗略有序,uuid 、hash 都达不到时间粗略有序,参考楼上的雪花算法
你希望你的 id 排序之后是毫无规律的随机排序(似乎会影响插入性能), 还是按照插入顺序先后排序(也就是插入时间),普通自增 id 天然有序。id 里面用时间因子作为前缀妥妥的,后面随便拼上 uuid 、md5 之类的,就基本上时间粗略有序了 |
33
silvernoo 2020-05-05 19:27:50 +08:00 via Android
md5 不是 128 位吗
|
34
Jacky23333 2020-05-05 19:38:49 +08:00 via Android
@changePro 我是说你这句话 “-“md5 生成的 userId 对索引不友好” 少误导其他人”
|
35
Jacky23333 2020-05-05 19:39:15 +08:00 via Android
@Jacky23333 我没觉得这句话误导他人了啊
|
36
jugelizi 2020-05-05 20:54:51 +08:00
似乎是 php 程序员
|
37
aflow 2020-05-05 21:05:11 +08:00
你这是在给后面埋坑,单体自增主键就好,md5 有重复的可能,不应该用来做唯一 id 。
不要自作聪明 |
38
v2Geeker 2020-05-05 22:04:02 +08:00
自增 id 好,这样建立的索引占用空间小,维护索引成本低,速度更快!
|
39
dallaslu 2020-05-05 22:25:23 +08:00 via iPhone 1
用户名 [email protected] 密码 forecast
用户名 [email protected] 密码 recast 所以还是乖乖用 UUID 吧。 另外,自增 id 和 UUID 可以同时用。主键自增,UUID 唯一约束。对外想用哪个就用哪个。 索引和存储空间的问题真不用担心。用户表邮箱、手机、用户名都有唯一约束,多一个也不见得会满。至于空间问题,最便宜的就是存储了…… |
40
n0tyet 2020-05-06 00:39:08 +08:00 via Android
把高性能 mysql 看完再继续思考
|
41
tairan2006 2020-05-06 00:57:04 +08:00 via Android
无意义,自增或者 snowflake
MySQL 的话别用 uuid |
42
Mithril 2020-05-06 01:13:37 +08:00
这么多人都没说到点子上。。
问题是 MD5 或者其它的摘要算法都是会冲突的啊。。。 算法设计目的是尽量阻止人为制造冲突,而不是完全没有冲突,毕竟只是摘要而已。小概率事件并不等同于不可能事件。 UUID 是直接在里面包含时间戳从而避免冲突的,你这个连时间戳都一块摘要了。。。 除非你自行设计了解决办法,不然完全不应该直接用 Hash 作为数据库主键。 |
43
3dwelcome 2020-05-06 01:23:20 +08:00 via Android
@Mithril 冲突可以切换到 64 位,128 位 hash,这种毕竟是少数,在一定数据量下属于可控范围,可以特殊处理。
|
44
icegreen 2020-05-06 08:42:50 +08:00
同意上面一位老哥的说法;
需要考虑你的数据库引擎以及索引结构, 以 mysql 的 innodb 来说, 主键无序,在插入的时候,会导致大量页分裂,降低索引效率; |
45
cheng6563 2020-05-06 08:44:47 +08:00 via Android
非有序的主键对索引不太友好吧
|
46
zchlwj 2020-05-06 09:28:52 +08:00
MD5 可是会冲突的
|
47
securityCoding 2020-05-06 10:33:17 +08:00
不要把问题复杂化 , 直接使用雪花算法就行了
|
48
Felldeadbird 2020-05-06 10:41:13 +08:00
雪花算法可以满足楼主的需求了。
|
50
tailf 2020-05-06 10:56:51 +08:00
主键使用这么长的字符串,确实会影响性能
|
51
lanterboy 2020-05-06 11:39:47 +08:00
19L 正解,如果楼主用的是 InnoDB 引擎,主键是聚簇的,乱序主键非常影响性能,建议把主键和业务唯一键分开,主键可以用雪花
|
52
inktiger 2020-05-06 11:46:06 +08:00
占用空间是肯定的,问题复杂化了也是肯定的,做之前先想想目的是什么,我是觉得一切根据自身原因来
|
53
tabris17 2020-05-06 11:48:20 +08:00
|
54
rimutuyuan 2020-05-06 12:03:55 +08:00
主键 id 不要动,新建 user_id 字段唯一索引就能满足
|
55
jsq2627 2020-05-06 12:37:47 +08:00
1. MySQL innodb 主键是聚族索引,用 uuid / md5() / base58 / base64 等生成的无序串做主键,数据量增长后插入性能急剧下降
2. 可以选择主键使用 AUTO_INCREMENT 整数,新增一列存储 uuid 等无序串并加索引。不过大查询量下,性能肯定不如主键这种聚族索引,可以通过缓存解决 3. uuid 也不完全是无序串,毕竟它是基于时间戳生成的,按一定规则进行解构重组,也能变得“有序”,作为主键据说性能也还行 https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/ 4. snowflake 完美解决了所有问题 |
56
jsq2627 2020-05-06 12:42:58 +08:00
至于用 md5 还是 uuid,楼主自己觉得开心请随意选择。只要保证没有冲突就好。君不见 b 站现在都用变种 base56 了
|
58
Heebe 2020-05-06 13:17:20 +08:00
我想问下,MD5 是你想出来的,还是有人教你的?如果有人教你的,赶紧删除了他,因为他可能让你损失 1 个亿。
我猜楼主是想做成一个无法被人类读取的订单号,来防止别人猜测业务量? 这叫分布式 ID,随便搜索下就有一堆的方案。 |
60
Cmdhelp 2020-05-06 13:40:55 +08:00
建议看一波 al 爪洼开发手册
|
61
3dwelcome 2020-05-06 13:55:59 +08:00
@Mithril 主键重复,就对自身加盐 hash,变成第二个,第三个 hash,循环多试几次,最后总能插进去的。
查询也是同样操作,查出来数据需要二次校对,如果订单不对就进行二次 /三次查询。 当然这些都是有前提的,表数据量必须在可控范围内。万一数据一多,冲突越多,肯定没戏。 |
62
sujin190 2020-05-06 14:03:17 +08:00
id 的话,感觉有顺序的更好一点吧,空间的感觉无所谓吧,反正内存磁盘也不值钱
|
63
Mithril 2020-05-06 14:08:26 +08:00
@3dwelcome 你这个前提是他不拿主键直接做查询,关键是既然不查询那为啥不直接自增 id 。。。
而且冲突就只是个概率,并不是真的可控,只是大概率不出问题。运气不好一直冲突也不是没可能的。 |
64
3dwelcome 2020-05-06 14:17:49 +08:00
@Mithril 我也不知道楼主为啥放着自增长 ID 不用,要另辟蹊径。也许就是楼上有人猜测的,防止对数据库暴力查询。因为实在想不出,这样做有别的什么理由。
至于谈到冲突,以前测试过对 MD5 的散列分布图,图上来看还是挺均匀的。 |
65
cloudzhou 2020-05-06 14:18:58 +08:00
如果不使用自增 id 的话,uuid 不行吗? snowflake 也可以
|
66
jasonding 2020-05-06 15:06:21 +08:00
已经确认存在两个不同的值经过 MD5 运算后可能会导致结果一致,万一不幸碰上了你准备怎么处理
|