Random 针对黑名单的随机唯一字符串

Random 针对黑名单的随机唯一字符串,random,unique,uuid,blacklist,Random,Unique,Uuid,Blacklist,我想创建一个固定长度的随机字符串(在我的用例中是8个字符),生成的字符串必须区分大小写,并且在黑名单中是唯一的。我知道这听起来像UUID,但我有一个特定的要求,阻止我使用它们 有些字符是不允许的,即i、l和1是相似的,O和0也是相似的 我最初的实现是可靠的,解决了任务,但执行得很差。我所说的糟糕是指它注定每天都会越来越慢 这是我当前要优化的实现: private function uuid() { $chars = 'ABCDEFGHJKLMNPQRSTVUWXYZabcdefghijk

我想创建一个固定长度的随机字符串(在我的用例中是8个字符),生成的字符串必须区分大小写,并且在黑名单中是唯一的。我知道这听起来像UUID,但我有一个特定的要求,阻止我使用它们

  • 有些字符是不允许的,即i、l和1是相似的,O和0也是相似的
  • 我最初的实现是可靠的,解决了任务,但执行得很差。我所说的糟糕是指它注定每天都会越来越慢

    这是我当前要优化的实现:

    private function uuid()
    {
        $chars = 'ABCDEFGHJKLMNPQRSTVUWXYZabcdefghijkmnopqrstvuwxyz23456789';
    
        $uuid = null;
        while (true) {
            $uuid = substr(str_shuffle($chars), 0, 8);
    
            if (null === DB::table('codes')->select('id')->whereRaw('BINARY uuid = ?', [$uuid])->first())) {
                break;
            }
        }
    
        return $uuid;
    }
    
    请不要再批评我了,我们生活在一个敏捷的世界中,这个实现是功能性的,并且很快就可以编写代码

    只需一小部分数据,它就能完美地工作。然而,如果我在黑名单中有1000万个条目,并尝试创建1000多个条目,它会失败,因为它需要30多分钟

    一个真正的用例是在数据库中有1000多万个条目,并尝试创建20000个新的唯一代码

    我想预先设定所有允许的值,但这太疯狂了: (24+24+8)^8=9.6717312e+13

    如果社区能为我指明正确的方向,那就太好了

    最好的, 尼古拉有两种选择:

  • 只需使用一个唯一的散列,并截断它,使其适合您的标识符的带宽。哈希有时会发生冲突,因此如果代码已经在使用中,您仍然需要检查数据库并重试

    s = "This is a string that uniquely identifies voucher #1.  Blah blah."
    h = hash(s)
    guid = truncate(hash)
    
  • 从递增计数器生成五个数字,随机生成三个。根据你的角色集,盗贼猜测代码的几率比140000分之一还要低

    u = Db.GetIncrementingCounter()
    p = Random.GetCharacters(3)
    guid = u + p
    

  • 我最终修改了方法:不再检查每个循环上是否存在uuid,例如50K DB检查,而是将生成的代码拆分为1000个代码的多个块,并在事务中发出INSERT IGNORE批处理查询


    如果受影响的行数与项目数相同(本例中为1000),我知道没有冲突,我可以提交事务。否则,我需要回滚块并生成另外1000个代码。

    它是否需要不可预测/不可用?为什么不能简单地使用递增计数器?不幸的是,它必须是不可预测的。想想凭证代码。你知道输出区分大小写的哈希吗?我脑子里想不出什么。然而,您的回答让我想到了两个想法:1)将RDBS表从uuid的一列拆分为3列或更多列。目标是通过使用更细粒度的WHERE子句来加速DB检查。2) 尝试使用NoSQL存储和检查黑名单。今天晚些时候我两个都要试试。