当更新MYSQL表时,While循环中的性能很慢


Slow Performance within While Loop when Updating MYSQL Table

当使用表product中的数据执行WHILE LOOP并更新同一数据库中的另一个表stock_figures时,下面的代码运行得非常慢。

代码遍历product中的每一行,从product_idwholesale_price中获取值,然后在product表上执行一些计算,然后用这些值更新stock_figures表。

如果有任何能提高我的查询性能的建议,我将不胜感激。

<?
// Retrieve data from database
$loop = " SELECT product_id, wholesale_price FROM product";
$query= mysql_query($loop);
while($rows=mysql_fetch_assoc($query))
    {
        $row = mysql_fetch_row($query);
        $id = $row[0];
        $price = $row[1];
?>

查询WHILE循环

<?
        $bawtry_stock = "
        SELECT product_id,
        ( kids_uk_j_105 + kids_c_17 + kids_c_18 + kids_c_19 + ... etc ) 
        AS SUM FROM product WHERE product_id = '$id'";
        $result_bawtry = mysql_query($bawtry_stock) or die (mysql_error());
        $line = mysql_fetch_row($result_bawtry);
        $bawtry = $line[1];
        $chain_stock = "
        SELECT product_id, 
        (quantity_c_size_26_chain + quantity_c_size_28_chain + quantity_c_size_30_chain +
        ... etc )
        AS SUM FROM product WHERE product_id = '$id'";
        $result_chain = mysql_query($chain_stock) or die (mysql_error());
        $line = mysql_fetch_row($result_chain);
        $chain = $line[1];
        /*
         * Declare the total value of all pairs from Bawtry, Chain
         */
        $totalpairs = $chain + $bawtry;
        /*
         * Insert values for stock to write to databse
         * Total stock for Bawtry, Chain
         * Total value of stock for Bawtry, Chain
         *
         */
        $bawtry_value = (float)($bawtry * $price);
        $chain_value = (float)($chain * $price);
        $total_value = (float)($price * ($bawtry + $chain));
        $sql2="
        UPDATE stock_figures SET 
        bawtry_stock='$bawtry',
        chain_stock='$chain',
        totalstock='$totalpairs',
        bawtry_value='$bawtry_value',
        chain_value='$chain_value',
        totalvalue='$total_value'
        WHERE id='$id'";
        $result2=mysql_query($sql2) or die (mysql_error());

?>
// close while loop
<? } ?>
<<p> 更新代码/strong>
$sql = "SELECT product_id, wholesale_price,
        (kids_uk_j_105 + kids_c_17 + kids_c_18 + kids_c_19 + kids_c_20 + kids_c_21 +
        ... )
        AS bawtry,
        (quantity_c_size_26_chain + quantity_c_size_28_chain + quantity_c_size_30_chain +
        ... )
        AS chain from product";
        $result = mysql_query($sql) or die (mysql_error());
        while ($line=mysql_fetch_assoc($result)) 
        {
            $id = $line['product_id'];
            $price = $line['wholesale_price'];
            $bawtry = $line['bawtry'];
            $chain = $line['chain'];
        /*
         * Declare the total value of all pairs from Bawtry, Chain 
         */
        $totalpairs = $chain + $bawtry;
        /*
         * Insert values for stock to write to database
         * Total stock for Bawtry, Chain
         * Total value of stock for Bawtry, Chain
         *
         */
        $bawtry_value = (float)($bawtry * $price);
        $chain_value = (float)($chain * $price);
        $total_value = (float)($price * ($bawtry + $chain));
        $sql2="
        UPDATE stock_figures SET 
        bawtry_stock='$bawtry',
        chain_stock='$chain',
        totalstock='$totalpairs',
        bawtry_value='$bawtry_value',
        chain_value='$chain_value',
        totalvalue='$total_value'
        WHERE id='$id'";
        $result2=mysql_query($sql2) or die (mysql_error());

然而,它仍然需要一个绝对的时间来完成。当我在末尾注释掉UPDATE语句时,它似乎运行得非常快。显然,这需要保留在代码中,所以我可能会将整个东西作为cronjob运行。

除非可以提出任何进一步的改进建议?

似乎你做了很多浪费的选择。

首先从表产品中选择一些数据,然后从同一表中再次选择每一行。两次。最后将其插入另一个表stock_figures.

你所做的唯一的操作就是把许多数字加在一起。

所有这些都可以在一个查询中完成。

select product_id,
       whole_sale_price, 
       sum(kids_uk_j_105, 
           kids_c_17,
           ...) as bawtry,
       sum(quantity_c_size_26_chain, 
           quantity_c_size_28_chain, 
           ...) as chain
  from products; 

如果这仍然花费很多时间,你需要检查一些服务器设置和行数

你所做的每一个写都是一个事务,根据你的acid级别,提交可能会很慢。将innodb-flush-log-at-trx-commit设置为2会加快写速度。

您正在对products-table进行全表扫描。我想这是有意为之,但如果这个表很大,读取它将花费一些时间,并且将所有这些行写回stock_figures将花费更长的时间。

考虑另一种方法。对于产品的每次写入(插入、更新或删除),都有一个触发器更新stock_figures中相应的行。它不仅可以消除批处理作业,还可以使stock_figures在任何给定时间都是正确的。

第一件事是:

 $row = mysql_fetch_row($query);
 $id = $row[0];
 $price = $row[1];

我不知道它是否适合你,但是你已经在你的while条件下使用了$rows,所以可能你应该把它改成:

 $id = $rows['product_id'];
 $price = $row['wholesale_price'];

接下来的两个查询你可以合并info:

SELECT product_id,
        ( kids_uk_j_105 + kids_c_17 + kids_c_18 + kids_c_19 + ... etc ) 
        AS `SUM` FROM product WHERE product_id = '$id'
UNION ALL
SELECT product_id, 
        (quantity_c_size_26_chain + quantity_c_size_28_chain + quantity_c_size_30_chain +
        ... etc )
        AS `SUM` FROM product WHERE product_id = '$id'

甚至:

SELECT product_id,
        ( kids_uk_j_105 + kids_c_17 + kids_c_18 + kids_c_19 + ... etc ) 
        AS `SUM1`,
        (quantity_c_size_26_chain + quantity_c_size_28_chain + quantity_c_size_30_chain +
        ... etc )
       AS `SUM2`
  FROM product WHERE product_id = '$id'

因为这两个查询是在同一个表上运行的。

但事实上,你可以使用一个查询来获得关于你的产品的所有信息,正如Andreas Wederbrand在他的回答中指出的。

但是还有更多的问题:

  1. 您使用旧的mysql_函数而不是mysqli_PDO,您的代码容易受到SQL注入

  2. 对于每个产品,你运行2个额外的查询(选择与联合所有,如果你走我的方式和更新)。

  3. 我不知道你有多少产品,但如果你有1000种或10000种产品,你不能指望它会很快。在这种情况下,您应该以某种方式在cron中运行脚本或刷新页面,并为少量产品(例如一次为10或100个产品)执行任务
  4. 您还应该考虑您的数据库结构是否是最好的。通常使用许多列作为你这里kids_uk_j_105, kids_c_17, kids_c_18不是最好的选择。

我希望你至少在product_id列设置了键primary_id

在执行许多SQL命令时,解析它们需要一些时间。您可以通过使用http://php.net/manual/en/mysqli.quickstart.prepared-statements.php来减少这种开销你得到多少,取决于情况。

预处理语句从安全性考虑也是很好的。

这个答案不会使这里的其他答案无效。通过减少查询的数量,分析它们的工作,如果可能的话合并它们来提高效率。