下面的函数吐出一个随机ID。我正在使用它来提供识别记录的确认别名。但是,我必须检查碰撞(但不太可能),因为我们只使用五位数长度。使用下面列出的允许字符,它可以达到大约3300万个组合。最终我们将获得500万左右的记录,因此碰撞成为一个问题。
检查欺骗别名效率低,资源量大。搜索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;
}
答案 0 :(得分:5)
为什么不在别名列上创建唯一索引?
CREATE UNIQUE INDEX uniq_alias ON MyTable(alias);
此时您可以尝试插入/更新,如果它返回错误,请生成新别名并重试。
答案 1 :(得分:1)
您真正需要做的是从基数10转换为基数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;
}
可能会出现一些语法错误,但你应该得到它的要点。
答案 2 :(得分:0)
你可以滚动自己的自动增量。这可能是相当低效的,因为你必须弄清楚你的增量在过程中的位置。例如,如果您将随机字符串中的位置指定为整数,并以(0)(0)(0)(0)(0)开头,它将等同于22222作为ID。然后得到下一个,只需将最后一个值递增到(0)(0)(0)(0)(1),它将转换为22223.如果最后一个值达到你的字符串长度,则将其设为0并增加倒数第二个等等......它不是随机的,但它会增加并且是唯一的。