V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
v2exblog
V2EX  ›  程序员

惊呆了,看到公司内部系统的生成数据库主键 ID 的代码以后,我的三观毁了。内附 Python 代码

  •  
  •   v2exblog · 271 天前 · 11960 次点击
    这是一个创建于 271 天前的主题,其中的信息可能已经有所发展或是发生改变。
    
    import random
    
    
    class IDGenerator:
        @classmethod
        def gen_primary_id(cls, length=11):
            prefix = random.choice('123456789')
            return prefix + ''.join([random.choice('0123456789')
                                     for i in range(length)])
    
    

    据说系统运行了几年,没碰见过碰撞的情况。我感觉我数学没学好,谁能告诉我这是哪一块的知识

    101 条回复    2021-04-28 11:11:56 +08:00
    1  2  
    GM
        1
    GM  
       271 天前
    你什么意思?明天来我办公室一下!

    /狗头
    xupefei
        2
    xupefei  
       271 天前 via iPhone
    高中数学,排列组合。
    thevita
        3
    thevita  
       271 天前
    数据量多吗
    0DBBFF
        4
    0DBBFF  
       271 天前
    我数学也不太好,是 9 * 10 的 11 次方吗? 这么多感觉碰撞几率是不是也不高啊
    guisheng
        5
    guisheng  
       271 天前 via iPhone
    随机用到了极致
    snw
        6
    snw  
       271 天前 via Android
    不怕碰撞吗?生成 10 万个 ID 大约有百万分之一概率发生碰撞。
    skyleft
        7
    skyleft  
       271 天前
    性能很差,b+tree 节点大量页分裂
    sujin190
        8
    sujin190  
       271 天前
    好歹加个日期啊,不会随着使用时间变长碰撞概率变高,所以楼主你想说的其实是你们司系统没啥人用的意思么,哈哈哈
    avastms
        9
    avastms  
       271 天前
    主键都唯一的,重复数据库就抛错了,用户一重试随机到别的就过了,不是没碰撞过,是没引起注意。
    ch2
        10
    ch2  
       271 天前   ❤️ 7
    但凡他知道有个包叫 uuid
    wellsc
        11
    wellsc  
       271 天前 via iPhone
    简单实用,不需要任何第三方包就解决需求
    janxin
        12
    janxin  
       271 天前   ❤️ 8
    没毛病,不要动

    赶紧提离职
    labulaka521
        13
    labulaka521  
       271 天前
    能跑就行
    fucku
        14
    fucku  
       271 天前
    又不是不能用
    Vegetable
        15
    Vegetable  
       271 天前   ❤️ 3
    哪怕是这个功能,我也会使用 str(randint(10**length,10**(length+1)))
    mixz
        16
    mixz  
       271 天前
    简单快速,赞
    gstqc
        17
    gstqc  
       271 天前 via Android   ❤️ 2
    贵司还没倒闭说明还是有两把刷子的
    CallMeReznov
        18
    CallMeReznov  
       271 天前   ❤️ 4
    imjamespond2020
        19
    imjamespond2020  
       271 天前 via Android
    改成 ubixtimestamp-uuid
    ksedz
        20
    ksedz  
       271 天前
    @Vegetable randrange
    Jooooooooo
        21
    Jooooooooo  
       271 天前
    可以用抛唯一键冲突重试的方法解决
    sillydaddy
        22
    sillydaddy  
       271 天前 via Android
    @snw #6
    概率应该比百万分之一高多了。对应的概率计算参考“生日问题”:

    https://zh.m.wikipedia.org/wiki/%E7%94%9F%E6%97%A5%E5%95%8F%E9%A1%8C

    我估计生成 10 万个 id 发生碰撞的概率应该大于千分之一。
    jeffwcx
        23
    jeffwcx  
       271 天前
    哈哈,这还不如 uuid 呢,如果需要 id 的顺序性可以用 snowflake
    snw
        24
    snw  
       271 天前
    @sillydaddy
    我刚才公式拉错了。用 excel 又模拟了一遍,10 万个 id 碰撞概率大约 4.877%。
    mind3x
        25
    mind3x  
       271 天前 via Android
    @sillydaddy 根据近似公式 1-1/exp(n^2/(2N)),n=10 万,N=900000000000,概率大于千分之 5 了。
    v2exblog
        26
    v2exblog  
    OP
       271 天前
    @mind3x 太秀了,请问怎么学这个公式,哪本书上有
    mind3x
        27
    mind3x  
       271 天前 via Android
    @v2exblog 就在 @sillydaddy 贴过的 Wikipedia 连接里
    pkupyx
        28
    pkupyx  
       271 天前
    也许数据库上有唯一索引重复就回滚吧
    jdandelion573
        29
    jdandelion573  
       271 天前 via Android
    说明数据库没人用
    ila
        30
    ila  
       271 天前 via Android
    要看其它代码
    ytmsdy
        31
    ytmsdy  
       271 天前   ❤️ 6
    冲突肯定是发生过的,只不过无法复现罢了!
    lightingtime
        32
    lightingtime  
       271 天前
    判断一下使用场景啊,qps 如果只有几,那么碰撞了就重新生成 a
    george404
        33
    george404  
       270 天前
    不得不佩服,大道至简,哈哈!!
    auh
        34
    auh  
       270 天前
    这一看就是组长干的事情。往往小兵在没有征得老大同意的情况下,是不敢这样操作的。
    wunsch0106
        35
    wunsch0106  
       270 天前
    我甚至觉得这是个段子
    jetyang
        36
    jetyang  
       270 天前   ❤️ 1
    重复了会插入报错,报错就再生成一个,大家不都是这么做的吗?抠鼻
    LudwigWS
        37
    LudwigWS  
       270 天前 via iPhone
    @snw excel 自己连 uuid 都没有,编程太不友好了。vba 很垃圾……
    securityCoding
        38
    securityCoding  
       270 天前 via Android
    233 还不如直接时间戳呢
    dangyuluo
        39
    dangyuluo  
       270 天前
    虽然代码很烂,但是公布自己就职公司的代码(勉强算得上是算法)好么?
    soulzz
        40
    soulzz  
       270 天前
    赶紧跑路
    weizhen199
        41
    weizhen199  
       270 天前
    @skyleft 你这么一说我突然好奇了。很多时候都会用 guid 来做主键。这样效率会很低?
    HashV2
        42
    HashV2  
       270 天前
    return str(random.randint(10**10, 10**11-1))
    HashV2
        43
    HashV2  
       270 天前
    快跑吧
    jinhan13789991
        44
    jinhan13789991  
       270 天前
    失败了再重试啊,总会成功的。而且及时发现了问题,也很难复现。
    有可能这个项目是压缩了开发周期,当初做他的程序员为了尽早完成。
    Leviathann
        45
    Leviathann  
       270 天前 via iPhone
    为什么就是不想用自增 id
    Felldeadbird
        46
    Felldeadbird  
       270 天前
    没说数据量啊。到百万或者千万 应该会出现过碰撞啊。
    Rache1
        47
    Rache1  
       270 天前
    python 这个 for 语法糖,真酸爽
    zjsxwc
        48
    zjsxwc  
       270 天前
    id 冲突了就 rollback 吗

    2333
    MinQ
        49
    MinQ  
       270 天前
    @ch2 uuid 太长了不适合做主键吧,我记得会导致 MySQL 性能下降
    MinQ
        50
    MinQ  
       270 天前
    我自己的方案是 snowflake 的 timestamp 设定一个 19 年的时间,然后往前位移 N 位缩短长度,最后转 Base32 截取,这样只需要 1X 位字母数字就能拿来做主键了
    要是觉得 Base32 看着不爽可以对着码表自己做个转换
    tabris17
        51
    tabris17  
       270 天前
    说明贵司业务量不大
    tankren
        52
    tankren  
       270 天前
    uuid 有现成的吧
    ganbuliao
        53
    ganbuliao  
       270 天前   ❤️ 1
    你们有日志吗?我觉得是碰撞到了了你们也不知道。就是插入数据报错,客户重试一下就好了还以为是网络抖动 、、):dog
    domodomo
        54
    domodomo  
       270 天前
    说明你们公司挺小的……
    PDdavon
        55
    PDdavon  
       270 天前
    @Vegetable #15 楼主公司的函数跟你这一行应该是等价的。。。。
    echowuhao
        56
    echowuhao  
       270 天前
    如果每个表不大,看不出什么问题。

    拿出来讨论的都是大公司的问题,其实大部分是小公司,没有那么多数据,如果在分库分表,那就更少了。
    37Y37
        57
    37Y37  
       270 天前
    简直神了,我都没想到这方法
    msg7086
        58
    msg7086  
       270 天前
    随机生成主键嘛,除了代码烂一点以外没啥问题。
    我如果需要随机主键我也会这样生成(当然不会写成这屎样就是了)。
    碰撞是小问题,重试就行。
    Cy1
        59
    Cy1  
       270 天前
    @weizhen199 guid 相比自增 ID 效率上肯定会低,但很低也不至于。既然选择了 guid 了,就别幻想有自增 ID 一样的性能了,底层的数据结构本身就决定了这个时候
    lichdkimba
        60
    lichdkimba  
       270 天前
    用户够少就不会有任何问题!
    preach
        61
    preach  
       270 天前
    握草 牛比 我居然还 copy 试了试
    Vegetable
        62
    Vegetable  
       270 天前
    @PDdavon 这不是就是吐槽设计的差代码也差么...
    Vegetable
        63
    Vegetable  
       270 天前
    其实我也用过差不多的逻辑,只要加上日期和简单的重试,的确是能用。

    https://imgur.com/a/qNx1UU4
    joyhub2140
        64
    joyhub2140  
       270 天前
    加点时间戳啊还是能用的,但扛不住高并发,不过这个系统几年下来都没碰撞,应该没啥人用吧
    tairan2006
        65
    tairan2006  
       270 天前
    @MinQ mysql8 已经有 uuid 和 binary 互转了
    Huelse
        66
    Huelse  
       270 天前
    random 模块产生碰撞的概率还是很低的,其本身就能规避一段时间问题

    希望有大佬能通过数学方式考证下,楼上有几位的公式感觉少考虑了一些影响因素
    jsuly
        67
    jsuly  
       270 天前
    我很好奇, 为什么要自己生成主键呀,不是都是主键,自增吗
    Latin
        68
    Latin  
       270 天前
    人家离职的原因就是不想堆屎山了吧
    MinQ
        69
    MinQ  
       270 天前
    @tairan2006 看到了,那个还是挺方便的,虽然公司还在用 5.7
    wsseo
        70
    wsseo  
       270 天前
    楼主跑路把
    pepesii
        71
    pepesii  
       270 天前
    你这就没明白了把,哈哈,这是明年的优化点,不然哪儿来的 KPI
    hahastudio
        72
    hahastudio  
       270 天前
    说起来,这么写和直接随机数字的区别是什么?
    怎么直觉上这种会更容易被碰撞
    fareware
        73
    fareware  
       270 天前
    这个设计的问题有两个
    1. 碰撞。这个还可以通过改代码来立即解决
    2. 数据库。使用 b+ 做索引的关系型数据库的性能问题,这个最严重,后期想优化更是难受。
    sss495088732
        74
    sss495088732  
       270 天前
    0.0 说实话这种生成唯一主键的是不是大家都用雪花算法....还没有遇到过性能问题
    MinQ
        75
    MinQ  
       270 天前
    @sss495088732 主要是好调好写,可以自己定制,最多依赖一个 zookeeper 或者 redis
    Cloutain
        76
    Cloutain  
       270 天前
    无序主键对于数据库是个考验 哈哈哈
    oolovexx
        77
    oolovexx  
       270 天前
    随机,可以的,牛批
    3dwelcome
        78
    3dwelcome  
       270 天前
    相同的主键没办法写入两次,数据库没冲突,是正常的。
    楼主的代码应该只贴出了一小半,如果冲突,大概率会重新生成一次。这样速度也不慢。
    JokeEnd
        79
    JokeEnd  
       270 天前
    用雪花算法
    TimPeake
        80
    TimPeake  
       270 天前
    我一个前端都知道弄个时间戳还能一定程度防止重复。。。。。
    KouShuiYu
        81
    KouShuiYu  
       270 天前   ❤️ 1
    说的应该就是我🐶

    ```js
    function getRandomStr(len) {
    const dictionary = '[email protected]#$%^&*()_+~:;,./<>?';
    const dictionaryLen = dictionary.length;
    let str = '';
    for (let i = 0; i < len; i += 1) {
    str += dictionary[Math.floor(getRandom(dictionaryLen))];
    }
    return str;
    }
    ```
    xiaochong0302
        82
    xiaochong0302  
       270 天前   ❤️ 1
    我懒鬼订单号:$this->sn = date('YmdHis') . rand(1000, 9999);

    没有大量用户高并发,这样又不是不能用,大不了后面再加一段随机数。
    nanjoyoshino
        83
    nanjoyoshino  
       270 天前
    这个可真的是太强了,点进来之前我完全没想到是这种方法
    watzds
        84
    watzds  
       270 天前
    怎么把核心代码公布出来了! 😄
    Wincer
        85
    Wincer  
       270 天前
    第二天楼主因为公开核心代码被开除了
    roudancongji
        86
    roudancongji  
       270 天前
    估计碰撞了就加个 retry,再来一遍
    johnsona
        87
    johnsona  
       270 天前 via iPhone
    @weizhen199 不然别人发明各种分布式 id 干嘛
    johnsona
        88
    johnsona  
       270 天前 via iPhone
    @roudancongji 好家伙 哈希碰撞策略被你学明白了
    l1ve
        89
    l1ve  
       270 天前
    if repeat {
    retry()
    }
    print("get random successful")
    luwill
        90
    luwill  
       270 天前
    uuid-4 变种
    opengps
        91
    opengps  
       270 天前
    别说的一无是处,这种自造逻辑有个天然优势就是自带防猜解特点
    cabing
        92
    cabing  
       270 天前
    插入失败 retry 就行。设计的有点东西,一般人绝对想不到如此有趣的设计。

    内网系统估计也没多少条数据。
    hanxiV2EX
        93
    hanxiV2EX  
       270 天前 via Android
    如果这个是用来生成用户 id,且用户量不大,比如内部的后台系统,那没啥大毛病,注册失败再重试一下,哈哈哈哈。
    cogitoxin
        94
    cogitoxin  
       269 天前 via iPhone
    叹为观止
    ccppgo
        95
    ccppgo  
       269 天前
    @xiaochong0302 哈哈哈, 只要没有分库分表, 直接弄个唯一索引, 报错就重试
    wangyzj
        96
    wangyzj  
       269 天前
    多大数量啊?
    echoZero
        97
    echoZero  
       269 天前
    跑就对了,不然你就会知道 mysql 主键不是自增时插入效率到底有多低。DBA 天天追着你进行优化
    fanyingmao
        98
    fanyingmao  
       269 天前
    又不是不能用,反正项目赚不赚钱和代码写得好坏关系不大。
    linyinma
        99
    linyinma  
       268 天前
    抛开业务谈代码都是耍流氓,存在必有其合理性
    zhuweiyou
        100
    zhuweiyou  
       268 天前
    公司内部系统, 一共就老板和测试两个人会访问, 没毛病
    1  2  
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1065 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 20:41 · PVG 04:41 · LAX 12:41 · JFK 15:41
    ♥ Do have faith in what you're doing.