0

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

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

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

这是示例表的链接:

它可以正常工作,但需要很长时间才能完成,因为一个表中有大约 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 />";
}
4

2 回答 2

1

如果两个表中都有索引(如果没有,则在两个字段的订阅者 ID 上创建)尝试使用不带 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。

于 2013-10-21T09:28:05.903 回答
1

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

要么你必须将你的输出分组subscriberid(这可能不会满足你想要的整理每个用户的列表订阅的结果),或者你必须更改架构:任何此类更改都必须一次性确定interspire_customfield应该与哪些值相关联每个emailaddress. 然后我会建议键入(并从该表和其中一个表interspire_customfieldemailaddress删除,具体取决于它是否应该与订阅者订阅相关联)。listidsubscriberid

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

$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需要(它似乎是非规范化的,因为它应该与listid其他表相关联)?您可能还希望考虑使用 MySQL 的本机时间数据类型而不是整数来存储时间值。

于 2013-10-21T09:56:36.280 回答