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

寻求一种短 UUID 解决方案

  •  
  •   SingeeKing · 2018-05-28 18:35:53 +08:00 · 7133 次点击
    这是一个创建于 2401 天前的主题,其中的信息可能已经有所发展或是发生改变。

    要求:

    1. 16 位以下
    2. db 范围内唯一
    3. PostgreSQL 可用

    UUID 是 32 位的,short UUID 总觉得有坑。。

    是否有什么好的实现方式?

    13 条回复    2018-06-01 17:33:15 +08:00
    Chyroc
        1
    Chyroc  
       2018-05-28 18:57:35 +08:00   ❤️ 2
    uuid 是 16 字节,如果是 16 进制( 0-9a-f )的,会有 32 个字符,有点长;所以考虑使用 64 进制,这样的话只有 16 个字符串;

    可以参考这个文章: https://blog.chyroc.cn/articles/2017-8-2-247355155.html
    lurenw
        2
    lurenw  
       2018-05-28 20:16:53 +08:00   ❤️ 1
    snowflake,64bit,刚好可以压缩成 16 个字符( 16 进制)
    beginor
        3
    beginor  
       2018-05-28 20:28:38 +08:00 via Android
    mark,期待万能的 V 友
    lukefan
        4
    lukefan  
       2018-05-28 20:31:03 +08:00   ❤️ 1
    mongodb 的 objectid, 12bit
    MiffyLiye
        5
    MiffyLiye  
       2018-05-28 20:41:17 +08:00   ❤️ 1
    UUID 类型是 128 bit,即 16 byte,并不是 32 个字符。

    你如果用 MySQL 没有原生 UUID 类型的话,我还可以推荐一下
    https://www.npmjs.com/package/snowflake-codon

    PostgreSQL 原生支持 UUID 就直接用吧。
    ericls
        6
    ericls  
       2018-05-28 20:45:41 +08:00 via iPhone   ❤️ 1
    hashids?
    fuyufjh
        7
    fuyufjh  
       2018-05-28 20:49:06 +08:00   ❤️ 1
    snowflake +1
    changnet
        8
    changnet  
       2018-05-28 23:47:45 +08:00 via Android   ❤️ 1
    我之前设计这个东西也想了很久。16bit 基本不可能做出来,在单一数据库里从 0 自增都不够用,算上分布式更加不够。最简单的方法就是 uuid 转 64 进制,随处可用。mongodb 的 object id 只是做集群还行。我做游戏的还要考虑合服,只能用数字,不支持 int64 这些,没有一个适用的。自己按具体需要设计一个,无非就是把时间戳,自增,业务唯一标识拼接一下,然后压缩处理,比如转 64 进制,时间戳不从 1970 算。

    网上还有些从概率上算的,认为碰撞概率小于多少便是唯一,那个确实比较短,看你的业务是不是能用
    sutra
        9
    sutra  
       2018-05-29 00:10:35 +08:00   ❤️ 1
    曾经拿 Javascript 写了一段让它表现得更短的代码,思路也就是 #1 的用更多的字符来编码:

    通常我们用 0-F 16 个字符来编码,我这里改成了用 62 个字符来编码:

    (不过由于 Javascript 浮点数最大能表达的数字的问题,我这段代码并不是最佳的)

    // var DIGITS = "0123456789ABCDEF"
    // var DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$&'()*+/:;=?@._~"
    var DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    var BASE = DIGITS.length
    var SEPARATOR = '-'

    function encodeNumber(num) {
    var digit
    var residual = Math.floor(num)
    var result = ''

    do {
    digit = residual % BASE
    result = DIGITS.charAt(digit) + result
    residual = Math.floor(residual / BASE)
    } while (residual > 0)

    return result
    }

    function decodeNumber(str) {
    var result = 0
    var digits = str.split('')
    var e, l = digits.length
    for (e = 0; e < l; e++) {
    result = (result * BASE) + DIGITS.indexOf(digits[e])
    }
    return result
    }

    function encodeUUID(uuid) {
    var results = []
    var s = uuid.replace(/-/g, '').toUpperCase()

    var uuidInts = [
    parseInt(s.substring(0, 8), 16),
    parseInt(s.substring(8, 16), 16),
    parseInt(s.substring(16, 24), 16),
    parseInt(s.substring(24, 32), 16)
    ]

    var i, l = uuidInts.length
    for (i = 0; i < l; i++) {
    results.push(encodeNumber(uuidInts[i]))
    }

    return results.join(SEPARATOR)
    }

    function decodeUUID(str) {
    var uuidStrs = str.split(SEPARATOR)
    var i, l = uuidStrs.length
    var result = ''
    var pad = '00000000'
    var s
    for (i = 0; i < l; i++) {
    s = decodeNumber(uuidStrs[i]).toString(16)
    s = pad.substring(0, pad.length - s.length) + s
    result += s
    }
    return result.replace(/([A-Za-z0-9]{8})([A-Za-z0-9]{4})([A-Za-z0-9]{4})([A-Za-z0-9]{4})([A-Za-z0-9]{12})/, "$1-$2-$3-$4-$5").toUpperCase()
    }

    module.exports = {
    encodeUUID: encodeUUID,
    decodeUUID: decodeUUID
    }
    owt5008137
        10
    owt5008137  
       2018-05-29 00:41:00 +08:00 via Android   ❤️ 1
    https://github.com/atframework/atsf4g-co/blob/sample_solution/src/server_frame/rpc/db/uuid.cpp#L79
    一级池 id 使用数据库自增,二级自己分配的一种方法。uint64,单个 type_id 内唯一
    honeycomb
        11
    honeycomb  
       2018-05-29 08:23:59 +08:00 via Android   ❤️ 1
    snowflake 8 字节,mongo 的 object 12 字节,udid (储存成 binary 的话) 16 字节
    sujin190
        12
    sujin190  
       2018-05-29 09:30:02 +08:00   ❤️ 1
    snowflake 麻烦是节点位太小了,很难自动根据当前部署机器和进程信息自动生成节点 id,在自动化分布式部署的时候可能会很麻烦

    mongodb 的 bson objectid 是 12 自己,base64 编码之后就是 16 字符啊,这就好了啊
    Chyroc
        13
    Chyroc  
       2018-06-01 17:33:15 +08:00
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3405 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 00:08 · PVG 08:08 · LAX 16:08 · JFK 19:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.