首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在php中优化for循环

在php中优化for循环
EN

Stack Overflow用户
提问于 2013-05-15 01:05:03
回答 3查看 145关注 0票数 0

我已经在php页面上运行了1000次foreach循环。foreach循环中的代码如下所示:

代码语言:javascript
复制
$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函数在每次循环运行时获得随机化值:

代码语言:javascript
复制
<td><?php echo $arr[array_rand($arr)] ?></td>

所以加载php页面需要很长的时间。有没有办法可以优化这段代码。因为每次循环运行时我都需要一个唯一的值

EN

回答 3

Stack Overflow用户

发布于 2013-05-15 01:12:52

问题不在于PHP foreach循环。如果你用RAND()命令你的MySQL表,你就犯了一个严重错误的。让我向你解释一下当你这样做的时候会发生什么。

每次您发出MySQL请求时,MySQL都会尝试将您的搜索参数(WHERE、ORDER BY)映射到索引,以减少数据读取。然后,它会将相关信息加载到内存中进行处理。如果信息太大,它将默认将其写入磁盘并从磁盘读取以执行比较。您希望不惜一切代价避免磁盘读取,因为它们低效、缓慢、重复,并且在特定情况下有时会完全错误。

当MySQL找到可能使用的索引时,它将改为加载索引表。索引表是存储位置和索引值之间的哈希表。例如,主键的索引表如下所示:

代码语言:javascript
复制
  id      location
  1         0 bytes in
  2         17 bytes in
  3         34 bytes in

这是非常高效的,因为即使是非常大的索引表也可以放入极少量的内存中。

为什么我要讨论索引?,因为通过使用RAND(),您可以阻止MySQL使用它们的ORDER BY RAND()强制MySQL为每行创建一个新的随机值。这需要MySQL复制临时表中的所有表数据,并添加一个具有RAND()值的新字段。此表太大,无法存储在内存中,因此将存储到磁盘。

当您告诉MySQL按RAND()排序并创建表时,MySQL将按对比较每一行(MySQL排序使用快速排序)。由于行太大,因此您需要在此操作中查看相当多的磁盘读取。当它完成时,它会返回,您将以巨大的成本获得数据-at。

有很多方法可以防止这种大规模的开销混乱。其中之一是从RAND()中选择ID到最大索引并限制为1。这不需要创建额外的字段。类似的堆栈问题还有很多。

票数 2
EN

Stack Overflow用户

发布于 2013-05-15 01:21:21

前面已经解释了为什么应该避免ORDER BY RAND(),所以我简单地提供了一种使用一些更快的查询来做到这一点的方法。

首先,根据您的表大小获取一个随机数:

代码语言:javascript
复制
SELECT FLOOR(RAND()*COUNT(*)) FROM first_names

其次,在限制中使用随机数

代码语言:javascript
复制
SELECT * FROM first_names $pos,1

不幸的是,我认为没有任何方法可以将这两个查询合并为一个查询。

您还可以执行一次SELECT COUNT(*) FROM first_names,存储数字,并在PHP中生成任意次数的随机$pos。

票数 0
EN

Stack Overflow用户

发布于 2013-05-15 01:23:56

如果您的主机支持mysqli或pdo,您应该切换到mysqli或pdo,但这样的东西应该可以工作。但是,如果两个表中都没有足够的记录,则必须确定要执行的操作(array_pad或包装索引并重新启动)

代码语言:javascript
复制
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ébastien Renauld的回答,更完整的解决方案可能是构造查询,如下所示

代码语言:javascript
复制
"SELECT givenname from first_names where id in (select id from first_names order by rand() limit ".$qty.")";
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16548900

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档