我在php页面上运行了一次foreach循环1000次。 foreach循环中的代码如下所示:
$first = mysql_query("SELECT givenname FROM first_names order by rand() LIMIT 1");
$first_n = mysql_fetch_array($first);
$first_name = $first_n['givenname'];
$last = mysql_query("SELECT surname FROM last_name order by rand() LIMIT 1");
$last_n = mysql_fetch_array($last);
$last_name = $last_n['surname'];
$first_lastname = $first_name . " " . $last_name;
$add = mysql_query("SELECT streetaddress FROM user_addresss order by rand() LIMIT 1");
$addr = mysql_fetch_array($add);
$address = $addr['streetaddress'];
$unlisted = "unlisted";
$available = "available";
$arr = array(
$first_lastname,
$address,
$unlisted,
$available
);
然后我每次循环运行时都使用array_rand函数来获取随机值:
<td><?php echo $arr[array_rand($arr)] ?></td>
因此加载php页面需要很长时间。有没有办法可以优化这段代码。因为每次循环运行时我都需要一个唯一的值
答案 0 :(得分:2)
问题不在于你的PHP foreach循环。如果您通过RAND()订购MySQL表,那么您将犯严重错误。让我向你解释当你这样做时会发生什么。
每次发出MySQL请求时,MySQL都会尝试将搜索参数(WHERE,ORDER BY)映射到索引,以减少读取的数据。然后它会将相关信息加载到内存中进行处理。如果信息太大,它将默认将其写入磁盘并从磁盘读取以执行比较。您希望不惜一切代价避免磁盘读取 ,因为它们效率低,速度慢,重复性差,并且在特定情况下有时可能会出现错误。
当MySQL找到可以使用的索引时,它将加载索引表。索引表是内存位置和索引值之间的哈希表。因此,例如,主键的索引表如下所示:
id location
1 0 bytes in
2 17 bytes in
3 34 bytes in
这非常有效,因为即使非常大的索引表也可以容纳少量内存。
为什么我要谈论指数? 因为使用RAND(),您正在阻止MySQL使用它们。 ORDER BY RAND()
强制MySQL为每一行创建一个新的随机值。这需要MySQL将所有表数据复制到所谓的临时表中,并添加带有RAND()值的新字段。该表太大而无法存储在内存中,因此它将存储到磁盘中。
当您告诉MySQL ORDER BY RAND()并创建表时,MySQL将按对比较每一行(MySQL排序使用quicksort)。由于行太大,您正在查看此操作的相当多的磁盘读取。完成后,它会返回,并且您获得的数据非常耗费。
有很多方法可以防止这种巨大的开销SNAFU。其中之一是从RAND()中选择ID到最大索引并限制为1.这不需要创建额外的字段。有很多类似的Stack问题。
答案 1 :(得分:0)
已经解释了为什么要避免使用ORDER BY RAND(),所以我只是提供了一种方法,可以通过一些更快的查询来实现。
首先根据您的表格大小获取一个随机数:
SELECT FLOOR(RAND()*COUNT(*)) FROM first_names
第二次使用限制中的随机数
SELECT * FROM first_names $pos,1
不幸的是,我认为没有办法将两个查询合并为一个。
此外,您可以执行SELECT COUNT(*) FROM first_names
,存储号码,并在PHP中随机生成$ pos随机$ pos。
答案 2 :(得分:0)
如果您的主机支持,您应该切换到使用mysqli或pdo,但这样的事情应该有效。如果您在任一表中没有足够的记录(array_pad或包装索引并重新启动),则必须确定要执行的操作
function getRandomNames($qty){
$qty = (int)$qty;
$fnames = array();
$lnames = array();
$address = array();
$sel =mysql_query("SELECT givenname FROM first_names order by rand() LIMIT ".$qty);
while ($rec = mysql_fetch_array($sel)){$fnames[] = $rec[0]; }
$sel =mysql_query("SELECT surname FROM last_name order by rand() LIMIT ".$qty);
while ($rec = mysql_fetch_array($sel)){ $lnames[] = $rec[0]; }
$sel =mysql_query("SELECT streetaddress FROM user_addresss order by rand() LIMIT ".$qty);
while ($rec = mysql_fetch_array($sel)){ $address[] = $rec[0]; }
// lets stitch the results together
$results = array();
for($x = 0; $x < $qty; $x++){
$results[] = array("given_name"=>$fnames[$x], "surname"=>$lnames[$x], "streetaddress"=>$address[$x]);
}
return $results;
}
希望这有帮助
<强>更新强>
根据SébastienRenauld的回答,一个更完整的解决方案可能是构建查询更像
"SELECT givenname from first_names where id in (select id from first_names order by rand() limit ".$qty.")";