使用表product
中的数据执行WHILE LOOP并更新同一数据库中的另一个表stock_figures
时,以下代码运行速度极慢。
代码循环遍历product
中的每一行,从product_id
和wholesale_price
获取值,然后在更新product
之前对stock_figures
表执行一些计算带有值的表。
我会感激任何可以改善查询性能的建议。
PHP WHILE LOOP
<?
// 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];
?>
循环中的查询
<?
$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
<? } ?>
更新代码
$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来运行。
除非可以建议进一步改进吗?
答案 0 :(得分:3)
看起来你做了很多浪费的选择。
首先从表格产品中选择一些数据,然后从同一个表格中再次选择每一行。两次。然后最后将其插入另一个表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将加快写入速度。
您正在对产品表执行全表扫描。我想这是有意的,但如果那个表读数很大,则需要一段时间,将所有这些行写回stock_figures将需要更长的时间。
考虑另一种方法。对于每次写入(插入,更新或删除)产品都有一个触发器更新stock_figures中的相应行。它不仅可以消除批处理作业,还可以使stock_figures在任何给定时间都正确。
答案 1 :(得分:1)
首先是:
$row = mysql_fetch_row($query);
$id = $row[0];
$price = $row[1];
我不知道它是否适合您,但您已经在while
条件下占用$行,所以可能应将其更改为:
$id = $rows['product_id'];
$price = $row['wholesale_price'];
接下来的2个查询可以组合信息:
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 在他的回答中指出。
但还有更多问题:
您使用旧的mysql_
函数而不是mysqli_
或PDO
,并且您的代码容易受到SQL注入攻击
对于每个产品,您运行2个额外的查询(如果您按照我的方式更新,请选择union all。)
kids_uk_j_105
,kids_c_17
,kids_c_18
不是最佳选择。我希望您至少在product_id
列设置了关键的primary_id。
答案 2 :(得分:0)
执行许多SQL命令时,解析它们需要一些时间。您可以使用http://php.net/manual/en/mysqli.quickstart.prepared-statements.php来减少此开销 你获得了多少,取决于具体情况。
出于安全原因,准备好的陈述也很有用。
这个答案不会使其他答案无效。尝试通过减少查询数量,分析他们的工作,在可能的情况下合并它们来提高效率等。