【问题标题】:Rolling Average Efficiency, php mysql滚动平均效率,php mysql
【发布时间】:2012-07-23 13:52:01
【问题描述】:

此脚本使用 php 和 mysql 计算一分钟滚动平均值,以减少异常值对我的数据的影响(一分钟 = 6 10 秒行)。它可以正确计算所有内容,但效率不足以一次处理超过 150 行。我想一次做尽可能多的行,可能在 5-10,000 之间,因为我的表超过 150,000,我每天输入大约 8,000 行。

关于如何使这个脚本更有效地运行,有人有什么建议吗?

谢谢!

<?php  

//connect to database  

mysql_connect("localhost","user","password");//database connection  
mysql_select_db("database");  

$result = mysql_query("SELECT Timestamp FROM table");  
if (!$result) {  
        die('Could not query:' . mysql_error());  
}  

//get number of rows in table  

$resultA = mysql_query("SELECT * FROM table");  
$num_rows = mysql_num_rows($result);  
echo "There are $num_rows rows.</br>";  

//select column to be averaged  

$resultB = mysql_query("SELECT PortRPMSignal FROM table");  
if (!$resultB) {  
        die('Could not query:' . mysql_error());  
}  

//set start equal to the first row you want to calculate the averages from, likely the first null row    

$start = 5;  

//calculate 1 minute average, the average is correct  

for($i = $start; $i<$num_rows; $i++){    
$output = mysql_result($result,$i);  
$test = mysql_result($resultB,$i)+mysql_result($resultB,$i-1)+mysql_result($resultB,$i-2)+mysql_result($resultB,$i-3)+mysql_result($resultB,$i-4)+mysql_result($resultB,$i-5);
$test2 = $test/6;  
$round = round($test2,4);  
$temp = mysql_query("SELECT Timestamp FROM table");  
if(!$temp){  
    die('Could not query:' . mysql_error());  
}  

//gets timestamp at row $i, and inserts new average value into that row in RPMAve column  

$time = mysql_result($result,$i);  
mysql_query("UPDATE table SET PortMinuteAveRPM = $round WHERE Timestamp =     '$time'");  
}  

【问题讨论】:

  • 你必须使用 MySQL 吗?看起来你不需要它。
  • mysql_query() 函数的 PHP 手册中所述:不鼓励使用此扩展。相反,应该使用MySQLiPDO_MySQL 扩展名。另请参阅MySQL: choosing an API 指南和related FAQ 了解更多信息。
  • 我开始使用 MySQL 来自动执行我所做的分析,而不是使用 Excel,您还有其他建议吗?

标签: php mysql performance average


【解决方案1】:

对于初学者,可以通过添加 COUNT() 聚合来清理此处的初始“计数”块:

$resultA = mysql_query("SELECT * FROM table");  
$num_rows = mysql_num_rows($result);  
echo "There are $num_rows rows.</br>"; 

改为:

$resultA = mysql_query("SELECT COUNT(*) FROM table");  
$row = mysql_fetch_array($result);  
$num_rows = $row[0];
echo "There are $num_rows rows.</br>"; 

这本身应该会大大加快速度。没有它,您将从表中选择所有数据 - 一个查询只会随着您放入表中的越多而变得越慢。

对于您正在计算的平均值,是否有任何无法在 MySQL 查询中直接完成的逻辑?比如:

UPDATE table SET PortMinuteAveRPM=(SELECT AVG(PortRPMSignal) FROM table WHERE Timestamp BETWEEN '$startTime' AND '$endTime') WHERE TimeStamp='$endTime'

如果可行的话,这可能会让您免于循环遍历结果。

【讨论】:

  • 谢谢!这可能有效,有没有办法使用该查询精确选择 6 行?我唯一担心的是时间戳列中是否存在不连续的行。
  • 是的,你应该可以像=(SELECT AVG(PortRPMSignal) FROM table WHERE Timestamp BETWEEN '$startTime' AND '$endTime' LIMIT 6)这样限制子查询。鉴于它是基于时间的,是否可以有不连续的行?
  • 是的,有些行必须删除,所以时间并不总是连续的。限制可能会起作用
  • 再次感谢,似乎比我原来的脚本快了不少
  • 没问题,很高兴我能帮上忙 =]
【解决方案2】:

听起来您正在尝试计算自回归移动平均线 (ARMA),但您对数据的解释以及捕获数据的方式存在许多问题。

如果您有完整的数据集(尽管您的问题暗示您没有),然后计算出包含所需记录数量的时间间隔并直接从数据库中获取,例如

SELECT a.timestamp as base, AVG(b.PortRPMSignal) 
FROM table a, table b
WHERE b.timestamp BETWEEN a.timestamp AND a.timestamp+INTERVAL 6 HOUR
GROUP BY a.timestamp

如果您想精简数据点,请尝试类似....

SELECT a.timestamp as base, AVG(b.PortRPMSignal) 
FROM table a, table b
WHERE b.timestamp BETWEEN a.timestamp AND a.timestamp+INTERVAL 6 HOUR
AND DATE_FORMAT(a.timestamp, '%i%s')='0000'
GROUP BY a.timestamp

虽然如果您没有完整的数据集但只有少量的抖动,一个更好的解决方案是使用自动增量 id 的模数从“a”中挑选出更少的行

【讨论】:

  • 我一直在寻找这个。当您没有正确的词汇来描述您的需求时,很难找到。自回归移动平均线。你是我的英雄。
【解决方案3】:

这只是一个开始,但你可以把这个放在一边

//get number of rows in table 
$resultA = mysql_query("SELECT * FROM table");  
$num_rows = mysql_num_rows($result);  
echo "There are $num_rows rows.</br>";

因为下面一行

$resultB = mysql_query("SELECT PortRPMSignal FROM table");  

...会给你一个结果集,你可以在上面使用 mysql_num_rows。

在查询中使用* 会增加数据库的负载。

在你的 for 循环中你有这个

$temp = mysql_query("SELECT Timestamp FROM table");  
if(!$temp){  
    die('Could not query:' . mysql_error());  
} 

这意味着每次循环时都会运行此查询,而您甚至没有使用结果。

我不知道mysqli是否会给你更好的性能,但你应该使用它。

【讨论】:

  • 我不熟悉mysqli,但我会研究一下,谢谢!
猜你喜欢
  • 1970-01-01
  • 2021-07-10
  • 2013-12-22
  • 1970-01-01
  • 2015-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多