如何改进和加速使用嵌套循环的PHP脚本?

时间:2013-10-21 08:28:40

标签: php mysql foreach while-loop inner-join

我写了一个PHP脚本,它连接两个表来显示这种格式的信息:

Jane Doe
Phone: 082 980 9514
Home Loan Applications (Active) - 17/07/2013
Credit Report (Free Report) (Unsubscribed) 12/06/2013

你会注意到第一个和最后一个名字在输出的第一行,然后是电话号码,然后是他们订阅的邮件列表。列表旁边是状态。 “活动”表示如果用户已选择退出邮件列表,则在显示未订阅日期时,用户尚未取消订阅并仍处于活动状态。然后是订阅者注册日期到某个邮件列表。

以下是示例表格的链接: Tables

它可以正常工作,但需要永远完成,因为1个表中有大约76,000个记录,而另一个表中大约有100,000个记录。我想问一下如何优化代码以加快脚本的建议。

这是我写的当前代码:

$resultarray = array();

$rs4 = mysqli_query($con1,"SELECT interspire_customfield.subscriberid, interspire_customfield.fname, interspire_customfield.lname, interspire_customfield.phone, emailaddress, subscribedate, unsubscribed, interspire_customfield.listid, listname FROM `interspire_subscriber` INNER JOIN `interspire_customfield` ON interspire_subscriber.subscriberid = interspire_customfield.subscriberid GROUP BY emailaddress");

while($row4 = mysqli_fetch_array($rs4)) {
        $resultarray[] = $row4['subscriberid'].",".$row4['fname'].",".$row4['lname'].",".$row4['phone'].",".$row4['emailaddress'];
}

foreach ($resultarray as $arrlist) {

    $arr = explode(',', $arrlist);
    $sid = $arr[0];
    $frstname = $arr[1];
    $lstname = $arr[2];
    $pnum = $arr[3];
    $emailadd = $arr[4];

    echo $frstname." ".$lstname."<br />";
    echo "Phone: ".$pnum."<br />";

    $rs5 = mysqli_query($con1,"SELECT interspire_customfield.subscriberid, subscribedate, unsubscribed, interspire_customfield.listid, listname FROM interspire_subscriber INNER JOIN interspire_customfield ON interspire_subscriber.subscriberid = interspire_customfield.subscriberid WHERE interspire_subscriber.emailaddress = '$emailadd' GROUP BY interspire_subscriber.listid");

    if (!$rs5) {
    printf("Error: %s\n", mysqli_error($con));
    exit();
}

    while($row5 = mysqli_fetch_array($rs5)) {
        $listname = $row5['listname'];
        $subdate = $row5['subscribedate'];
        $unsub = $row5['unsubscribed'];

        if($unsub == "0"){
            $stat = "Active";
        }else{
            $stat = date('d/m/Y', $unsub);
        }

        $subdt = date('d/m/Y', $subdate);

        echo "* $listname ($stat) - $subdt <br />";
    }
        echo "<br />";
}

2 个答案:

答案 0 :(得分:1)

如果在两个表中都有索引(如果没有,在两个字段的subscriberid上创建它),请尝试使用不带JOIN的查询:

SELECT 
ic.subscriberid, 
ic.fname, 
ic.lname, 
ic.phone, 
ic.listid, 
emailaddress, 
subscribedate, 
unsubscribed, 
listname 
FROM `interspire_subscriber` isub, `interspire_customfield` ic
WHERE isub.subscriberid = ic.subscriberid
GROUP BY emailaddress

使用缓冲区在打印前存储字符串。您可以将字符串值或数组与join()方法或ob_start一起使用。

答案 1 :(得分:1)

您的预期输出需要确定每个电子邮件地址的一组姓名和电话号码:但由于interspire_subscriber将多个subscriberid值与一个emailaddress相关联,因此加入{ {1}}(包含姓名和电话号码数据)不是1:1;因此,电子邮件地址可能与多个不同的姓名和电话号码相关联。

您必须按interspire_customfield对输出进行分组(可能无法满足您整理每个用户列表订阅的预期结果),或者您必须更改架构:任何此类更改必须包含一次性确定来自subscriberid的值应与每个interspire_customfield相关联。然后我会建议在emailaddress上键入interspire_customfield(并从该表中删除emailaddress并从其中一个表中删除listid,具体取决于它是否应与订阅者或订阅)。

进行这些更改后,您可以执行以下操作:

subscriberid

至于速度,您应该确保在$dbh = new PDO("mysql:dbname=$dbname;charset=utf8", $username, $password); $qry = $dbh->query(' SELECT emailaddress, c.fname, c.lname, c.phone, s.subscribedate, s.unsubscribed, s.listname FROM interspire_subscriber AS s JOIN interspire_customfield AS c USING (emailaddress) ORDER BY emailaddress, s.listid '); if ($qry) { echo '<ol>'; $row = $qry->fetch(); while ($row) { $current_email = $row['emailaddress']; echo '<li>', htmlentities($row['fname']),' ',htmlentities($row['lname']),'<br/>', 'Phone: ',htmlentities($row['phone']), '<ul>'; do { $unsub = $row['unsubscribed']; echo '<li>',htmlentities($row['listname']), ' (',$unsub ? 'Active' : date('d/m/Y', $unsub),')', ' - ',date('d/m/Y', $row['subscribedate']), '</li>'; } while ($row = $qry->fetch() and $row['emailaddress'] == $current_email); echo '</ul>', '</li>'; } echo '</ol>'; } 表上定义了interspire_subscriber上的综合索引;以及(emailaddress, listid)UNIQUE表上的interspire_customfield索引。

虽然我们处于此状态,但您可能希望考虑是否需要(emailaddress)(它似乎是非规范化的,因为它应该与其他表中的interspire_subscriber.listname相关联)?您可能还希望考虑使用MySQL的本机时态数据类型而不是整数来存储时态值。