我写了一个函数,它生成一个随机id makeid();
。为了确保id是唯一的,我有一个SQL语句来检查id是否已经存在。
$does_id_exist = mysql_query("SELECT COUNT(*) AS count FROM signups WHERE affid='$affid'");
if(mysql_num_rows($does_id_exist) == 1)
{
#loop function and perform query again
}
else
{
#insert record
}
所以我在循环函数时遇到了问题。如何循环我的函数makeid()
并执行$does_id_exist
检查以确保每个ID
是唯一的。
--UPDATE——只是澄清一下——我的代码生成了一个类似YES@281E
的id,但在我将这个id插入用户记录之前。我只需要验证是否有其他用户已经有了这个id。如果有其他用户有这个id,则该事件必须触发我的函数来创建一个新的id,例如WOW!29E3
,并再次检查sql/query,以确保没有其他用户有那个id。如果失败,则继续循环,如果id可用,则结束并插入。
您可以只在数据库表上使用主键,也可以使用类似的东西:
<?php
// the id to insert
$newId = null;
// populate with results from a SELECT `aff_id` FROM `table`
$currentIds = array();
// prepopulate
for( $i=0; $i<100000; $i++ )
{
$currentIds[] = "STRING_" + rand();
}
// generate at least one id
do
{
$newId = "STRING_" + rand();
}
// while the id is taken (cached in $currentIds)
while( in_array($newId, $currentIds) );
// when we get here, we have an id that's not taken.
echo $newId;
?>
输出:
STRING_905649971(运行时间95ms);
我绝对不建议重复运行查询。如果你的流量足够大,也许在插入之前进行最后一次检查。
不要执行COUNT(*)
,因为你不需要知道有多少行(它应该是0或1,因为你需要Id唯一),所以即使DB找到了你的行,它仍然会检查整个表是否计数。您真的很关心是否有1行,所以只需选择具有该ID的行,这就足够了。您还应该避免使用rand()
——正如您所看到的,这并没有帮助,而且在找到"空闲插槽"之前,您无法预测您可以执行多少循环。使用一些可预测的东西,比如日期前缀,或者前缀每天递增。任何有助于缩小数据集的内容。但现在(伪代码!):
$id = null;
while( $id == null ) {
$newId = 'prefix' . rand();
mysql_query("SELECT `affid` FROM `signups` WHERE `affid`='${newId}'");
if( mysql_num_rows() == 0) {
$id = newId;
break;
}
}
确保数据库已编入索引,以加快速度。
编辑:我同意任何缓存都有助于加快速度(你可以根据@Josh的例子自己轻松添加),但我认为这是在错误的地方修复的。如果可能的话,重新思考生成ID的方式。它并不需要自动递增,但比rand()
更可预测的东西会对你有所帮助。如果您的ID不需要容易记忆,并且将其按顺序排列也没有任何安全问题,那么可以使用除10之外的其他基数的数字(即,使用26将使用所有数字+字母,因此您将以PREFIX-AX3TK
结尾,因此可以根据您的需要使用字符串,同时您可以轻松地快速生成下一个ID