2

このスクリプトは、php と mysql を使用して 1 分間のローリング平均を計算し、外れ値がデータに与える影響を減らします (1 分 = 6 10 秒行)。すべてを正しく計算しますが、一度に 150 行を超える計算を行うほど効率的ではありません。テーブルが 150,000 を超えており、1 日あたり約 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

自己回帰移動平均 (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 に答える
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 に答える
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 に答える