生成一个连续的五位字母数字ID

12

概述:

下面的函数会输出一个随机ID,我使用它来提供一个确认别名以识别记录。但是,由于我们只使用了五位数字长度,因此必须检查重复(尽管不太可能)。使用下面列出的允许字符,大约有3300万多种组合。最终,我们将达到大约五百万条记录,因此冲突成为问题。

问题:

检查重复别名是低效且资源消耗大的。500万条记录是一大堆需要搜索的数据,特别是当不同用户同时进行此搜索时。

我的问题:

有没有一种方式可以“自动增加”此函数允许的组合?这意味着我只需要搜索最后一个记录的别名并继续移动到下一个组合。

已知限制:

我意识到代码将与下面的函数有很大不同。我也意识到mysql具有数字ID的自动增量功能,但项目需要使用由“23456789ABCDEFGHJKLMNPQRSTUVWXYZ”这些允许字符组成的五位别名。在这个问题上我的手被绑住了。

我的当前函数:

 public function random_id_gen($length)
 {
     $characters = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
     $max = strlen($characters) - 1;
     $string = '';

     for ($i = 0; $i < $length; $i++) {
         $string .= $characters[mt_rand(0, $max)];
     }

     return $string;
 }

5
感谢您提出了一个结构良好的问题,给您点个赞 :) - Joshua - Pendo
4
谢谢,pendo。SO社区很棒。随意发一个糟糕的问题是不尊重的。 - k to the z
1
创建一个单独的表格,包含唯一的ID并标记哪些已被使用(这是我们解决问题的方法)。 - Grumpy
@gumbo,你是对的。我改了它。 - k to the z
1
Tgr,如果我们说“数据库中已经有两个别名是相同的”,那么这个说法可能是正确的。但是,由于我们要命名一个别名并说“别名x在数据库中的可能性有多大”,所以生日问题并不适用。例如,如果你说“在给定的一组人中,两个人的生日是04/01的概率有多大”,这并不等同于说“在给定的一组人中,两个人的生日相同的概率有多大”。 - k to the z
显示剩余5条评论
3个回答

5
为什么不在别名列上创建唯一索引?
CREATE UNIQUE INDEX uniq_alias ON MyTable(alias);

在这个时候,你可以尝试插入/更新操作,如果返回错误,则生成一个新的别名并重试。


1
引用 Clay Davis 的话:“shiiiiiiiiiiiiit”。感谢您,先生,我认为这是最简单的解决方案。这就是肩膀上的效果。 - k to the z

1

你真正需要做的是将数字从十进制转换为基数strlen($characters)

PHP自带一个内置的base_convert函数,但它并不完全符合你的要求,因为它会使用数字零、一和字母'o',而这些在你的版本中不存在。所以你需要一个函数来映射base_convert的值到/从你的值:

function map_basing($number, $from_characters, $to_characters) {
    if ( strlen($from_characters) != strlen($to_characters)) {
       // ERROR!
    }

    $mapped = '';
    foreach( $ch in $number ) {
       $pos = strpos($from_characters, $ch);
       if ( $pos !== false ) {
          $mapped .= $to_characters[$pos];
       } else {
          // ERROR!
       }
    }

    return $mapped;
}

现在你已经有了这个:

 public function next_id($last_id)
 {
    $my_characters = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
    $std_characters ='0123456789abcdefghijklmnopqrstuv';

    // Map from your basing to the standard basing.
    $mapped = map_basing($last_id, $my_characters, $std_characters);

    // Convert to base 10 integer and increment.
    $intval = base_convert($mapped, strlen($my_characters), 10);
    $intval++;

    // Convert to standard basing, then to our custom basing.
    $newval_std = base_convert($intval, 10, strlen($my_characters));
    $newval = map_basing($newval_std, $std_characters, $my_characters);


    return $newval;
 }

可能会有一些语法错误,但你应该能够理解它的意思。

0
你可以自己编写自增逻辑。但它可能相当低效,因为你必须找出自增在哪个位置上。例如,如果你将随机字符串的位置分配为整数,并以(0)(0)(0)(0)(0)开始,那么它将等同于ID 22222。然后要获得下一个值,只需将最后一个值增加到(0)(0)(0)(0)(1),这将转换为22223。如果最后一个达到了字符串长度,则将其设置为0并将倒数第二个增加,以此类推。虽然不完全是随机的,但它将是唯一且自增的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接