数据库表中唯一主键 id 用 32 位的 md5 算出来的值是否可行? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ex1gtnim7d
V2EX    数据库

数据库表中唯一主键 id 用 32 位的 md5 算出来的值是否可行?

  •  1
     
  •   ex1gtnim7d 2020-05-05 15:12:58 +08:00 6334 次点击
    这是一个创建于 2060 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如:

    用户表中,将用户邮箱+密码的值去做 MD5,得出来的值作为 userId

    订单表中,将订单数据+时间戳的值去做 MD5,得出来的值作为订单 Id

    主要的疑问是,32 位的 id 是否过于占用空间?

    以及其他缺点希各位 V 友能发表下看法。

    66 条回复    2020-05-06 15:06:21 +08:00
    Takamine
        1
    Takamine  
       2020-05-05 15:16:24 +08:00 via Android
    ……这样做的意义是什么,强行想让主键 id 和业务含义关联起来吗。
    ajaxfunction
        2
    ajaxfunction  
       2020-05-05 15:18:04 +08:00
    要是用户密码改了呢? 之前生成的 userid 和现在的 userid 不一样,系统不就乱了吗?
    简单的问题复杂化了啊!
    creedowl
        3
    creedowl  
       2020-05-05 15:18:32 +08:00 via Android
    要是用户改密码怎么办,如果是想要隐藏真实 id 可以用 hashid
    订单可以用雪花算法
    hbolive
        4
    hbolive  
       2020-05-05 15:18:45 +08:00
    @Takamine 这样的 id 看起来很酷。。
    nvkou
        5
    nvkou  
       2020-05-05 15:21:27 +08:00 via Android
    uuid 也是这么做的。只不过人家用一去不回头的时间做种子之一。
    没有必要重复发明轮子
    ex1gtnim7d
        6
    ex1gtnim7d  
    OP
       2020-05-05 15:21:51 +08:00
    @Takamine
    @ajaxfunction
    @creedowl
    只是想简单的生成一个唯一 id 而已,用户改密码没什么影响,id 还是那个 id
    luopengfei14
        7
    luopengfei14  
       2020-05-05 15:23:18 +08:00
    用户一旦修改邮箱、密码,你就找不回来 userId,而且 md5 生成的 userId 对索引不友好。
    简单点直接用自增 id 当作 userId,考虑多的可以用雪花算法生成 userd,一般够用。

    还有 md5 、uuid 字符串理论上避免不了重复的可能
    yukiloh
        8
    yukiloh  
       2020-05-05 15:23:30 +08:00
    用户登陆用账号行不,手机行不,你要做 3 个 userid 吗
    ex1gtnim7d
        9
    ex1gtnim7d  
    OP
       2020-05-05 15:24:56 +08:00
    @nvkou 倒也没有说想重复造轮子,不过确实没有想过直接调用已有的算法去生成,是个不错的方式
    chendy
        10
    chendy  
       2020-05-05 15:26:18 +08:00
    负载不大自增就够用了
    至于 “32 位过于占用空间?”…emm ???
    ex1gtnim7d
        11
    ex1gtnim7d  
    OP
       2020-05-05 15:26:49 +08:00
    好吧,我的表达存在歧义,其实这个 userid 并不作为对外公开的值,也不提供给用户登录使用,只是内部对用户的一个标识,可以理解为就是用户表的主键 id
    murmur
        12
    murmur  
       2020-05-05 15:28:12 +08:00
    uuid 也比 md5 好啊,你的用户量多少,少的话可以,多的话得考虑下防装,你估计是看了 mongo 那个主键,别人是有算法的,可以保证在数据结构上的一些优化
    murmur
        13
    murmur  
       2020-05-05 15:29:13 +08:00
    @Takamine 有些业务需要随机化主键,否则破解你一个接口 id 直接递增数据就爬一遍了
    ex1gtnim7d
        14
    ex1gtnim7d  
    OP
       2020-05-05 15:31:27 +08:00
    @murmur 想请教一下防装是什么意思
    linvon
        15
    linvon  
       2020-05-05 15:32:29 +08:00
    @kerb15 防撞吧
    changePro
        16
    changePro  
       2020-05-05 15:34:09 +08:00 via Android
    “md5 生成的 userId 对索引不友好” 少误导其他人
    wangyzj
        17
    wangyzj  
       2020-05-05 15:36:17 +08:00
    不是不行, 百害无一利
    changePro
        18
    changePro  
       2020-05-05 15:37:34 +08:00 via Android
    首先,为什么要这样做?主键 ID 几乎都是 fixed length,磁盘内存、又便宜,索引不是问题。md5 也可以看作是 UUID,用 UUID 做主键大部分是为了解决分布式的一些问题,题主是为了折腾?
    Jacky23333
        19
    Jacky23333  
       2020-05-05 15:39:59 +08:00 via Android   3
    你这样做会严重影响插入性能,因为会频繁导致页分裂跟行移动,产生空间碎片
    Jacky23333
        20
    Jacky23333  
       2020-05-05 15:41:26 +08:00 via Android   1
    @changePro 我觉得没毛病啊
    msg7086
        21
    msg7086  
       2020-05-05 15:52:31 +08:00 via Android
    主键不与业务相关。你看看你的想法是否违反了这条惯例。
    xuanbg
        22
    xuanbg  
       2020-05-05 15:55:41 +08:00
    占空间倒没什么,现在存储这么便宜……

    问题是:
    1 、效率低,算一个哈希值也是有开销的。2 、建立索引效率受影响。

    然后,直接用 uuid 他不香吗?
    changePro
        23
    changePro  
       2020-05-05 16:32:24 +08:00
    @Jacky23333 会导致性能下降,如果缓存不命中,导致大量磁盘 IO 。因为相同的数据,page 更多了。buffer pool 设计好的话的话,其实也还好
    PopRain
        24
    PopRain  
       2020-05-05 16:34:06 +08:00
    如果不想用 uuid, 推荐 Twitter 雪花(SnowFlake)算法,一个 64 位整数
    l3n641
        25
    l3n641  
       2020-05-05 16:53:23 +08:00
    不建议这样做,主键越长 索引也占用空间.如果数据量大的话,添加和更新数据会很大影响性能.如果是 mysql 的 inodb 的话.其他的普通索引都会包含主键键值.这时候会更加占用空间.
    saulshao
        26
    saulshao  
       2020-05-05 17:06:15 +08:00
    通常情况下,主键字段就选择单纯的整数 /大整数 /无符号整数就行。
    凡是需要某种业务相关计算来"产生"主键值的动作,都是花费很高并且没什么收益的方案。
    yinzhili
        27
    yinzhili  
       2020-05-05 17:11:28 +08:00
    不建议。这样的订单号过长,且可读性几乎等于 0 。
    PHPer233
        28
    PHPer233  
       2020-05-05 17:33:08 +08:00 via Android
    一个简单的 id 让你搞得这么复杂
    yjxjn
        29
    yjxjn  
       2020-05-05 17:38:25 +08:00
    雪花算法不香么?
    yjxjn
        30
    yjxjn  
       2020-05-05 17:39:42 +08:00
    @kerb15 防止撞库。说人话的意思就是防止让人家穷举猜到了
    joooooker21
        31
    joooooker21  
       2020-05-05 18:09:55 +08:00
    单体应用可以用自增主键
    分布式应用可以用雪花算法或 uuid

    你说的这种方法没有意义且消耗资源
    xiangyuecn
        32
    xiangyuecn  
       2020-05-05 18:16:39 +08:00
    设计 ID 结构最核心的一点,我觉得应当是时间粗略有序,uuid 、hash 都达不到时间粗略有序,参考楼上的雪花算法

    你希望你的 id 排序之后是毫无规律的随机排序(似乎会影响插入性能), 还是按照插入顺序先后排序(也就是插入时间),普通自增 id 天然有序。id 里面用时间因子作为前缀妥妥的,后面随便拼上 uuid 、md5 之类的,就基本上时间粗略有序了
    silvernoo
        33
    silvernoo  
       2020-05-05 19:27:50 +08:00 via Android
    md5 不是 128 位吗
    Jacky23333
        34
    Jacky23333  
       2020-05-05 19:38:49 +08:00 via Android
    @changePro 我是说你这句话 “-“md5 生成的 userId 对索引不友好” 少误导其他人”
    Jacky23333
        35
    Jacky23333  
       2020-05-05 19:39:15 +08:00 via Android
    @Jacky23333 我没觉得这句话误导他人了啊
    jugelizi
        36
    jugelizi  
       2020-05-05 20:54:51 +08:00
    似乎是 php 程序员
    aflow
        37
    aflow  
       2020-05-05 21:05:11 +08:00
    你这是在给后面埋坑,单体自增主键就好,md5 有重复的可能,不应该用来做唯一 id 。
    不要自作聪明
    v2Geeker
        38
    v2Geeker  
       2020-05-05 22:04:02 +08:00
    自增 id 好,这样建立的索引占用空间小,维护索引成本低,速度更快!
    dallaslu
        39
    dallaslu  
       2020-05-05 22:25:23 +08:00 via iPhone   1
    用户名 [email protected] 密码 forecast
    用户名 [email protected] 密码 recast

    所以还是乖乖用 UUID 吧。

    另外,自增 id 和 UUID 可以同时用。主键自增,UUID 唯一约束。对外想用哪个就用哪个。

    索引和存储空间的问题真不用担心。用户表邮箱、手机、用户名都有唯一约束,多一个也不见得会满。至于空间问题,最便宜的就是存储了……
    n0tyet
        40
    n0tyet  
       2020-05-06 00:39:08 +08:00 via Android
    把高性能 mysql 看完再继续思考
    tairan2006
        41
    tairan2006  
       2020-05-06 00:57:04 +08:00 via Android
    无意义,自增或者 snowflake

    MySQL 的话别用 uuid
    Mithril
        42
    Mithril  
       2020-05-06 01:13:37 +08:00
    这么多人都没说到点子上。。
    问题是 MD5 或者其它的摘要算法都是会冲突的啊。。。
    算法设计目的是尽量阻止人为制造冲突,而不是完全没有冲突,毕竟只是摘要而已。小概率事件并不等同于不可能事件。
    UUID 是直接在里面包含时间戳从而避免冲突的,你这个连时间戳都一块摘要了。。。
    除非你自行设计了解决办法,不然完全不应该直接用 Hash 作为数据库主键。
    3dwelcome
        43
    3dwelcome  
       2020-05-06 01:23:20 +08:00 via Android
    @Mithril 冲突可以切换到 64 位,128 位 hash,这种毕竟是少数,在一定数据量下属于可控范围,可以特殊处理。
    icegreen
        44
    icegreen  
       2020-05-06 08:42:50 +08:00
    同意上面一位老哥的说法;
    需要考虑你的数据库引擎以及索引结构, 以 mysql 的 innodb 来说, 主键无序,在插入的时候,会导致大量页分裂,降低索引效率;
    cheng6563
        45
    cheng6563  
       2020-05-06 08:44:47 +08:00 via Android
    非有序的主键对索引不太友好吧
    zchlwj
        46
    zchlwj  
       2020-05-06 09:28:52 +08:00
    MD5 可是会冲突的
    securityCoding
        47
    securityCoding  
       2020-05-06 10:33:17 +08:00
    不要把问题复杂化 , 直接使用雪花算法就行了
    Felldeadbird
        48
    Felldeadbird  
       2020-05-06 10:41:13 +08:00
    雪花算法可以满足楼主的需求了。
    ppyzzz
        49
    ppyzzz  
       2020-05-06 10:49:33 +08:00
    @hbolive 老哥,你这个回复是我在所有评论里面最接近真相的
    tailf
        50
    tailf  
       2020-05-06 10:56:51 +08:00
    主键使用这么长的字符串,确实会影响性能
    lanterboy
        51
    lanterboy  
       2020-05-06 11:39:47 +08:00
    19L 正解,如果楼主用的是 InnoDB 引擎,主键是聚簇的,乱序主键非常影响性能,建议把主键和业务唯一键分开,主键可以用雪花
    inktiger
        52
    inktiger  
       2020-05-06 11:46:06 +08:00
    占用空间是肯定的,问题复杂化了也是肯定的,做之前先想想目的是什么,我是觉得一切根据自身原因来
    tabris17
        53
    tabris17  
       2020-05-06 11:48:20 +08:00
    14v45mJPBYJW8dT7
        54
    14v45mJPBYJW8dT7  
       2020-05-06 12:03:55 +08:00
    主键 id 不要动,新建 user_id 字段唯一索引就能满足
    jsq2627
        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 完美解决了所有问题
    jsq2627
        56
    jsq2627  
       2020-05-06 12:42:58 +08:00
    至于用 md5 还是 uuid,楼主自己觉得开心请随意选择。只要保证没有冲突就好。君不见 b 站现在都用变种 base56 了
    jsq2627
        57
    jsq2627  
       2020-05-06 12:43:22 +08:00
    @jsq2627 * 变种 base58
    Heebe
        58
    Heebe  
       2020-05-06 13:17:20 +08:00
    我想问下,MD5 是你想出来的,还是有人教你的?如果有人教你的,赶紧删除了他,因为他可能让你损失 1 个亿。

    我猜楼主是想做成一个无法被人类读取的订单号,来防止别人猜测业务量?
    这叫分布式 ID,随便搜索下就有一堆的方案。
    Mithril
        59
    Mithril  
       2020-05-06 13:38:16 +08:00
    @3dwelcome 插入数据的时候主键重复了。。这怎么特殊处理。。
    Cmdhelp
        60
    Cmdhelp  
       2020-05-06 13:40:55 +08:00
    建议看一波 al 爪洼开发手册
    3dwelcome
        61
    3dwelcome  
       2020-05-06 13:55:59 +08:00
    @Mithril 主键重复,就对自身加盐 hash,变成第二个,第三个 hash,循环多试几次,最后总能插进去的。
    查询也是同样操作,查出来数据需要二次校对,如果订单不对就进行二次 /三次查询。

    当然这些都是有前提的,表数据量必须在可控范围内。万一数据一多,冲突越多,肯定没戏。
    sujin190
        62
    sujin190  
       2020-05-06 14:03:17 +08:00
    id 的话,感觉有顺序的更好一点吧,空间的感觉无所谓吧,反正内存磁盘也不值钱
    Mithril
        63
    Mithril  
       2020-05-06 14:08:26 +08:00
    @3dwelcome 你这个前提是他不拿主键直接做查询,关键是既然不查询那为啥不直接自增 id 。。。
    而且冲突就只是个概率,并不是真的可控,只是大概率不出问题。运气不好一直冲突也不是没可能的。
    3dwelcome
        64
    3dwelcome  
       2020-05-06 14:17:49 +08:00
    @Mithril 我也不知道楼主为啥放着自增长 ID 不用,要另辟蹊径。也许就是楼上有人猜测的,防止对数据库暴力查询。因为实在想不出,这样做有别的什么理由。
    至于谈到冲突,以前测试过对 MD5 的散列分布图,图上来看还是挺均匀的。
    cloudzhou
        65
    cloudzhou  
       2020-05-06 14:18:58 +08:00
    如果不使用自增 id 的话,uuid 不行吗? snowflake 也可以
    jasonding
        66
    jasonding  
       2020-05-06 15:06:21 +08:00
    已经确认存在两个不同的值经过 MD5 运算后可能会导致结果一致,万一不幸碰上了你准备怎么处理
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1033 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 23:16 PVG 07:16 LAX 15:16 JFK 18:16
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86