跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 有没有什么生成随机不重复的唯一 ID 且足够短的好办法?
未分類
23 10 月 2020

有没有什么生成随机不重复的唯一 ID 且足够短的好办法?

有没有什么生成随机不重复的唯一 ID 且足够短的好办法?

資深大佬 : kaiki 11

B 站的 bv 号那种就感觉可以,但是太长,我想生成只有几位的数字+大小写字母组合的随机字符表作为 ID,但是怕万一随机出以前出过的 ID
大佬有話說 (67)

  • 資深大佬 : lxk11153

    搞一个 mysql 拿来自增 ID 不就好了

  • 資深大佬 : opengps

    足够短跟容量是有直接制约的。首先得估算出最小的容量,然后研究下组成,然后计算出最小多长。

    我当初设计过一款唯一访问 key,思路你参考下:
    key 的参与构造字符,我用的是数字 10,大写字母 26,小写字母 26,虽然还可以用一部分单位符号但我没选,这样我的 key 只要 8 位字符就是 62 的 8 次方,就远远超过了 imei 的 15 纯数字位组合,而且还留下了巨大的空间,至于去重,我是每次随机生成完都检查一下是否已存在实现的,如果你对查重有性能要求的话需要重点改造下这个地方

  • 資深大佬 : lpts007

    @opengps 62^8 < 10^15

  • 資深大佬 : ziseyinzi

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

  • 主 資深大佬 : kaiki

    @lxk11153 主要是想无规律,不可逆,如果位数都能保持一致就最好了

  • 資深大佬 : meinjoy

    我得方法是截取 uuid,随机一个起始位置比如 2,想要 5 位的 id,就 uuid.substring(2,7)就行了

  • 主 資深大佬 : kaiki

    @meinjoy 和随机生成没什么区别,我打算随机生成几位数字大小写字母然后写入一个表中,绑定一个对应的数字 ID,查询的时候随机 ID 返回数字 ID,写入的时候查询随机 ID 是否存在,存在就重来一次生成过程。
    这样随机的 ID 就和数字 ID 没有任何规律可循了。

  • 資深大佬 : 594duck

    数据足够多的时候又要来问怎么查得快

  • 資深大佬 : helloworld000

    https://leetcode.com/problems/random-pick-with-blacklist/

  • 資深大佬 : black11black

    我倒是很好奇,用 hash 确实是保证基本不重复了,冲撞了的情况该怎么办呢?

  • 資深大佬 : Perry

    @black11black 先了解冲撞的概率有多少再谈需要不需要考虑这种情况

  • 資深大佬 : lazydog

    github 上应该一搜一大把吧,你可以搜搜看 unique id

  • 資深大佬 : black11black

    @Perry 很有趣的回答,难道系统的设计者可以这么思考问题:因为冲撞是极小概率发生事件,所以不需要考虑?

  • 資深大佬 : Cooky

    预先生成检测重复,用的时候再取

  • 資深大佬 : z7356995

    数字 id 后端加密加盐一下,使用前再解密,应该比在表中查快一点

  • 資深大佬 : opengps

    @lpts007 嗯,imei 用途中,有些位数不是数学里的所有数值都用的上,我是从实用角度足够用了,说的不严谨

  • 資深大佬 : avenger

    Snowflake 了解一下

  • 資深大佬 : AndyAO

    让我想起来了微软的全局标识符 GUID

  • 資深大佬 : iConnect

    要短,要快,还要随机,满足三个条件,最简单就是随机预生成放号码池。

  • 資深大佬 : Perry

    @black11black 这不是很正常的一个 tradeoff ? GUID 也有极小概率能被碰撞,依据你的逻辑一个普通应用还要去做好这样的碰撞情况?

  • 資深大佬 : 0bit

    用 uuid v4 生成,然后转成 short uuid

  • 資深大佬 : yuzo555

    主要求短,那么 hash 算法肯定重复概率高。
    又想要短,又想要无规律,只能用主自己在 #7 提出来的方案了。

  • 資深大佬 : black11black

    @Perry 服了,大神当然都是不处理边际情况的,不用回了 block 了

  • 資深大佬 : cmdOptionKana

    第一考虑总量。另一个思路是考虑频率,比如,如果生成 ID 的间隔必然超过一秒,那用 timestamp 转 64 进制,再加个两位随机字符就可以了。

  • 資深大佬 : cmdOptionKana

    @black11black 这个 block 冤枉了,忽略小概率情况是很常见的做法,小规模系统连密码库的 nonce (要求唯一性) 都可以采用随机数。

  • 資深大佬 : Perry

    @black11black 使用正确的情况下,大部分 hash 或者 GUID 的碰撞概率都是 astronomically low 的,如果你觉得这算是边际情况的话那你可以去处理。听到与自己观点不一样的声音就 block 对方这个行为有点巨婴了。

  • 資深大佬 : black11black

    @cmdOptionKana 问题是你不做,真撞了怎么办呢,比如现在有个坏东西,故意给你传两份 md5 一样的 hexstring

  • 資深大佬 : workg

    Date.now().toString(36) + Math.random().toString(36).slice(2) ?

  • 資深大佬 : cmdOptionKana

    @workg 看情况,Date.now()精确到毫秒,如果一秒内并发生成很少 ID,则可以除以 1000 精确到秒,这样 ID 可以短些。另外 toString 最高只能转为 36 进制,如果用其他方法转为 64 进制,还可以再缩短 ID 长度。

  • 資深大佬 : Maboroshii

    snowflake 转 base32

  • 資深大佬 : imdong

    先给主分享自己有过的两个类似的经验吧:

    15 年,公司接了一个电商买公交乘车码的东西,乘客手机购买后生成数字序列号给司机验证后可乘车。

    由于需要手输,所以数字要短,当时做过一些研究,主可以参考一下结论(一定量情况下,直接随机数和瞎搞胡搞的看起来随机的没差):

    ![image.png]( https://i.loli.net/2020/10/16/7wYaKPWrDjBNgkt.png)

    ![image.png]( https://i.loli.net/2020/10/16/qFEaijgyPBhs7rD.png)

    然后附上我前段时间搞得一个离线 CDK,里面又一些思路主可以参考:

    顺序生成,但是通过在二进制上一定的变换,可以得到看似随机的结果,但和原值一一对应,不重复。

    https://www.qs5.org/Post/680.html

    ( 15 年时我还很菜,别喷,虽然我现在依然菜,但谁喷我 ,我就画圈圈骂谁。)

  • 資深大佬 : mcluyu

    uuidgen

  • 資深大佬 : threebr

    感觉就是找一个有序数列到同样长度无序数列能够一一对应的函数,不行就像 19l 说的,预生成这样的对应列表

  • 資深大佬 : newtype0092

    @black11black 你的每段代码都处理了因为 cpu 二极管电位异常导致计算结果不正确的异常了么?
    没有的话请 block 我,这种边际情况都不处理你不配和我们讨论~

  • 資深大佬 : manhere

    hashids

  • 資深大佬 : shuqin2333

    short uuid

  • 資深大佬 : gamexg

    https://hashids.org/
    https://github.com/pjebs/optimus-go

    都是直接对 id 进行可逆加密的办法。
    另外也可以考虑直接用 aes 等方式加密。

  • 資深大佬 : cmdOptionKana

    @imdong 随机唯一码,如果不是事先生成,一般思路都是 时间+设备码+随机数,传统的 UUID 与现在流行的 snowflake 都是这个思路。如果不加入一些环境常数(比如随时间而变化、随设备而变化、随地点变化),那肯定不管怎么折腾都只是一个随机数(随机数+随机数=随机数)。

  • 資深大佬 : cheng6563

    全随机是真的会重的,一般要带上时间,但这样就长了。可以预先随机一些 ID 放池子里,用一个取一个,只是这样比较慢

  • 資深大佬 : imdong

    @cmdOptionKana 这个不是真正的随机,是可以用于数据库自增字段,然后对自增字段进行一定的处理,使其变得看起来像是随机数一样(结果定长)。

    而且连续两个数之间可能看不出规律(不知道处理方式的情况下)。

  • 資深大佬 : a570295535

    就用上那些方式,
    1 、用代码生成 100 万个 id 或更多
    2 、去重复并放进数据库
    3 、用户来一个取一个
    完成!
    随取随用,只有一开始你自己麻烦一次,这样不仅短还不会重复!

  • 資深大佬 : unixeno

    @black11black md5 这种已经能有快速碰撞算法的 hash 讨论这个就没意义了,你要用 sha256 还能撞吗?你要是现在能找到碰撞的 sha256,第一件事儿应该是去发个论文
    单论生日攻击,sha256 你要达到 10^-15 的碰撞概率需要 1.5*10^31 个数据,这个概率啥概念?大概是下一秒小行星撞地球然后人类灭绝的概率
    至于 10^31 啥概念?现在人类所有数码化保存的信息总量也才不到 10^22
    与其担心极小概率的碰撞,你不如先担心一下高能粒子打到你 CPU 上造成 bit 反转让你 hash 算错了

  • 主 資深大佬 : kaiki

    重复问题上,再次随机就行了,大家没必要那么严肃。
    那么是实时查写号码池,还是提前准备号码池呢?

  • 資深大佬 : imn1

    如果你所说的场景,不必随机,只要时间序列做一个最小转换就行了,只要外部不知道转换算法,看上去就是随机的
    网站或者业务的一些 id,往往还包含了轻量的分类信息,这个就不是单纯随机就能完成的需求了

  • 資深大佬 : popoer

    snowflake 不香吗

  • 資深大佬 : wyz123723

    @black11black 你这问题就和有人真破解了 sha256 了怎么办

  • 資深大佬 : wyz123723

    hash 碰撞的概率比一坨量子突然汇聚成一个特别喜欢你的美女的概率还要小

  • 資深大佬 : jaylee4869

    redis increment

  • 資深大佬 : xuewuchen

    GUID 吧。。

  • 資深大佬 : killergun

    感觉你这个需求不就是短地址生成

  • 資深大佬 : imhui

    如果是单机服务,线型同余 或许可以试一下

  • 資深大佬 : azoon

    主要求不高,这么随便的话。就每次生成随机字符串时判断数据库是否存,存在就再次生成,就好了吧。
    我之前给别人做了个拍照预约系统的订单号就这么搞。

  • 資深大佬 : xuanbg

    @imdong 我搞了个编码生成器,就是顺序生成,但是通过查表变换,可以得到看似随机的结果,但和原值一一对应,不重复。

    代码很简单:
    for(int i = len – 1; isEncrypt && i > 0; code = garble(code)) {
    –i;
    }
    private static String garble(String str) {
    int len = str.length();
    String first = len > 2 ? str.substring(0, 1) : “”;
    String high = len > 3 ? str.substring(1, len – 2) : “”;
    String low = String.valueOf(set.get(str.substring(len – 2, len)));
    return high + low + first;
    }

  • 資深大佬 : Jooooooooo

    了解一下鸽笼原理

  • 資深大佬 : tamer

    @wyz123723 那么请问有没有办法能加快这样的汇聚呢,很急,在线等

  • 資深大佬 : xuanbg

    @xuanbg set 就是 00-99 的密码表,通过查表可以得到一个对应的预生成的随机值。加密后的数字理论上必需得到密码本、交换方法和交换次数才能还原加密前的数字,三者缺一不可。

  • 資深大佬 : tabris17

    hashids

  • 資深大佬 : iyangyuan

    预生成,最简单最可靠。
    假设长度 6 位,每一位可选[a-z][0-9],那么就是 20 亿的容量(不够用增加长度即可)。
    每次预生成,不能太多,也不能太少,那么我们可以控制前 2 位递增(00,01…zy,zz),每次生成固定前 2 位,后 4 位全量,这样就是百万级别的容量,应该够用一段时间,快消耗完时依此类推。
    这样就能满足生成快、读取快,不重复,足够短。

  • 資深大佬 : TomVista

    36 进制 id,每次随机一个数字进行随机递增,产生随机 id.

  • 資深大佬 : TomVista

    @TomVista 带大小写的话,就是 62 进制,8 位就是 2 百万亿,够用到天荒地老了,随机范围 1000 的话,还在 2 千亿级别.

  • 資深大佬 : JCZ2MkKb5S8ZX9pq

    看了上的思路,忽然想到固定排列组合+伪随机,自定义个种子,是不是也可以?

  • 資深大佬 : xcatliu

    最近发现的一个 star 很多的 https://github.com/ai/nanoid,看了下功能很全,比如可以自定字典和长度:

    “`js
    import { customAlphabet } from ‘nanoid’
    const nanoid = customAlphabet(‘1234567890abcdef’, 10)
    model.id = nanoid() //=> “4f90d13a42”
    “`

  • 資深大佬 : phithon

    看到上有提到 hashids 的了
    https://hashids.org/

  • 資深大佬 : dreasky

    美团有个库 https://github.com/Meituan-Dianping/Leaf/blob/master/README_CN.md

  • 資深大佬 : black11black

    @wyz123723
    @unixeno
    @newtype0092
    不是概率小不小的问题,我觉得你作为设计者,当然不可能允许设计范围内存在一种小概率情况让程序不知道怎么处理,设计外情况当然不算在内,电位异常不是你能控制的,但你能控制的范围内你肯定要处理,所以我就问碰撞了怎么处理,上有人也说过了碰撞了就重随机这种简单答案,或者有人说用 sha256 可以基本避免恶意设计碰撞,这都是解决方案,你有方案就贡献方案,没方案就不回,没什么必要杠来杠去的。

    再说你真设计一个系统,你当然要考虑设计安全性,像我说的你如果完全没有碰撞处理方案,那随便一个人稍微有点恶意,传了经过设计的特殊字串,就能让你的程序抛出异常,这是完全有可能发生的情况而不是什么极小概率事件,显然设计过系统的都没法接受。也不知道现在杠精这么多都在杠什么,如果你们写程序的时候就真不加碰撞处理的代码,那我们也不用讨论什么了,道不同不相为谋,没必要

  • 資深大佬 : Deepseafish

    @black11black 「或者有人说用 sha256 可以基本避免恶意设计碰撞,这都是解决方案」
    这不按照你的逻辑还是没有考虑碰撞的情况吗?这不等于还是在说碰撞概率低,怎么就又是解决方案了。

  • 資深大佬 : black11black

    @Deepseafish 尝试跟杠精讨论是我的错,block 了不用回了

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具