2

此脚本使用 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'");  
}  
4

3 回答 3

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'

如果可行的话,这可以使您免于循环遍历结果。

于 2012-07-23T14:09:43.640 回答
1

听起来您正在尝试计算自回归移动平均线 (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”中挑选出更少的行

于 2012-07-23T15:01:40.997 回答
0

这只是一个开始,但您可以将这一点装箱

//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是否会给你更好的性能,但你应该使用它。

于 2012-07-23T14:02:46.650 回答