MySQL在foreach循环中查询 - 性能问题?

时间:2015-09-03 08:15:04

标签: php mysql

数组showcasef每页包含20个项目。我在foreach循环中执行了3个不同的查询,这是60个查询(仅用于循环,还有其他查询)。

<?php

foreach($showcasef as $itemf){

      $sf_id = $itemf['sf_id'];
      $sf_url = $itemf['sf_url'];
      $sf_title = $itemf['sf_title'];

      $sf_urltitle = post_slug($sf_title);

      // Fetch number of favs

      $stmt = $conn->prepare("SELECT COUNT(f_id) FROM favourites WHERE f_showcaseid=?");
      $stmt->bind_param("i", $sf_id);
      $stmt->execute();
      $stmt->bind_result($numfFavs);
      $stmt->fetch();
      $stmt->close();

      // Fetch class

      $stmt = $conn->prepare("SELECT avg(r_class) FROM ranks WHERE r_showcaseid=?");
      $stmt->bind_param("i", $sf_id);
      $stmt->execute();
      $stmt->bind_result($sf_class);
      $stmt->fetch();
      $stmt->close();

    // Fetch number of classes

    $stmt = $conn->prepare("SELECT COUNT(r_class) FROM ranks WHERE r_showcaseid=?");
    $stmt->bind_param("i", $sf_id);
    $stmt->execute();
    $stmt->bind_result($numfClasses);
    $stmt->fetch();
    $stmt->close();
?>

在此处呈现HTML

<?php } ?>

这是一个严重的性能问题,还是这些特定的查询相对简单?如果我保持列索引,它应该可以执行数百万行(可能)吗?或者可以优化/简化查询?

这是我如何获得showcasef

$stmt = $conn->prepare("SELECT s_id,s_url,s_title FROM showcase WHERE s_userid=? ORDER BY s_date DESC LIMIT $skippingFactor, 20");
$stmt->bind_param("i", $u_id);
$stmt->execute();
$stmt->bind_result($sf_id,$sf_url,$sf_title);

while($stmt->fetch())
{
     $showcasef[] = [
         'sf_id' => $sf_id,
         'sf_url' => $sf_url,
         'sf_title' => $sf_title
     ];
}

$stmt->close();

2 个答案:

答案 0 :(得分:3)

这里有一些建议。

重复使用准备好的陈述

您正在循环中创建三个预准备语句。为什么不只创建一次语句,然后使用多个绑定重用它们?

<?php

$stmt1 = $conn->prepare("SELECT COUNT(f_id) FROM favourites WHERE f_showcaseid=?");
$stmt1->bind_param("i", $sf_id);
$stmt1->bind_result($numfFavs);
$stmt2 = $conn->prepare("SELECT avg(r_class) FROM ranks WHERE r_showcaseid=?");
$stmt2->bind_param("i", $sf_id);
$stmt2->bind_result($sf_class);
$stmt3 = $conn->prepare("SELECT COUNT(r_class) FROM ranks WHERE r_showcaseid=?");
$stmt3->bind_param("i", $sf_id);
$stmt3->bind_result($numfClasses);

foreach($showcasef as $itemf) {
  $sf_id = ...

  $stmt1->execute();
  $stmt1->fetch();
  /* if the fetch succeedes then $numfFavs will contain the count */

  $stmt2->execute();
  ...

  $stmt3->execute();
  ..
}

$stmt1->close();
$stmt2->close();
$stmt3->close();

使用单个查询计算行数并计算平均值

您可以将第二个和第三个语句组合成一个SQL查询:

SELECT COUNT(r_class) AS cnt, AVG(r_class) AS average
FROM   ranks
WHERE  r_showcaseid=?

使用单个查询代替foreach循环

根据之前的建议,您可以获得更好的表现。但你真的确定你需要一个foreach循环吗?

如果您的ID由另一个查询返回,则使用子查询代替foreach循环更好:

SELECT f_showcaseid, COUNT(f_id)
FROM favourites
WHERE f_showcaseid IN (SELECT id FROM ... WHERE ...)
GROUP BY f_showcaseid

或者您可以为查询提供ID列表:

SELECT f_showcaseid, COUNT(f_id)
FROM favourites
WHERE f_showcaseid IN (?,?,?,?,?)
GROUP BY f_showcaseid

(如果ID数量不固定,您可以动态创建?列表)

答案 1 :(得分:0)

我认为你可以在一个查询中执行此操作。

如下所示: -

SELECT f_showcaseid, COUNT(f_id), avg(r_class), COUNT(r_class)
FROM ranks WHERE r_showcaseid IN (".implode(',', $showcasef).")
GROUP BY f_showcaseid

当然,要使用参数,你需要做得更优雅: -

<?php

    $stmt = $conn->prepare("SELECT f_showcaseid, COUNT(f_id), avg(r_class), COUNT(r_class)
    FROM ranks WHERE r_showcaseid IN (".implode(',', str_split(str_repeat('?', count($showcasef)), 1)).")
    GROUP BY f_showcaseid");

    foreach($showcasef as $itemf)
    {
        $stmt->bind_param("i", $itemf['sf_id']);
    }

    $stmt->execute();
    $stmt->bind_result($numfClasses);
    $stmt->fetch();
    $stmt->close();

?>