[vz-dev] Performanceoptimierung MeterInterpreter
Andreas Goetz
cpuidle at gmx.de
Wed Apr 24 17:31:07 CEST 2013
Hallo Zusammen,
beim Testen von VZ auf dem eher schwachbrüstigen Raspberry Pi ist mir
aufgefallen, dass Anfragen des Frontends nach einer bestimmten Anzahl
von Tupeln bei niedrigen Zoomstufen dadurch beantwortet werden, dass der
Interpreter durch alle Rows eines Resultsets läuft und diese gem. mit
Hilfe von packageSize auf die gewünschte Anzahl Tupel aggregiert. Dabei
müssen zum einen recht viele Daten verarbeitet werden, zum anderen diese
auch erstmal aus MySQL abgeholt werden.
Alternativ lassen sich die Daten jedoch bereits in MySQL aggregieren.
Die untenstehende Methode erledigt das und kann in MeterInterpreter
eingefügt werden (siehe unterer Teil nach EmptyIterator).
Ich freue mich über Feedback/ Testergebnisse:
/**
* Get raw data
*
* Optimized version for thinning meter data
*
* @param string|integer $groupBy
* @return Volkszaehler\DataIterator
*/
protected function getData() {
// get timestamps of preceding and following data points as a
graciousness
// for the frontend to be able to draw graphs to the left and
right borders
if (isset($this->from)) {
$sql = 'SELECT MIN(timestamp) FROM (SELECT timestamp FROM
data WHERE channel_id=? AND timestamp<? ORDER BY timestamp DESC LIMIT 2) t';
$from = $this->conn->fetchColumn($sql,
array($this->channel->getId(), $this->from), 0);
if ($from)
$this->from = $from;
}
if (isset($this->to)) {
$sql = 'SELECT MAX(timestamp) FROM (SELECT timestamp FROM
data WHERE channel_id=? AND timestamp>? ORDER BY timestamp ASC LIMIT 2) t';
$to = $this->conn->fetchColumn($sql,
array($this->channel->getId(), $this->to), 0);
if ($to)
$this->to = $to;
}
// common conditions for following SQL queries
$sqlParameters = array($this->channel->getId());
$sqlTimeFilter = self::buildDateTimeFilterSQL($this->from,
$this->to, $sqlParameters);
if ($this->groupBy) {
$sqlGroupFields = self::buildGroupBySQL($this->groupBy);
if (!$sqlGroupFields)
throw new \Exception('Unknown group');
$sqlRowCount = 'SELECT COUNT(DISTINCT ' . $sqlGroupFields .
') FROM data WHERE channel_id = ?' . $sqlTimeFilter;
$sql = 'SELECT MAX(timestamp) AS timestamp, SUM(value) AS
value, COUNT(timestamp) AS count'.
' FROM data'.
' WHERE channel_id = ?' . $sqlTimeFilter .
' GROUP BY ' . $sqlGroupFields;
}
else {
$sqlRowCount = 'SELECT COUNT(*) FROM data WHERE channel_id
= ?' . $sqlTimeFilter;
$sql = 'SELECT timestamp, value, 1 AS count FROM data WHERE
channel_id=?' . $sqlTimeFilter . ' ORDER BY timestamp ASC';
}
$this->rowCount = (int) $this->conn->fetchColumn($sqlRowCount,
$sqlParameters, 0);
if ($this->rowCount <= 0)
return new \EmptyIterator();
// potential to reduce result set?
if ($this->rowCount > $this->tupleCount && !$this->groupBy) {
$packageSize = floor($this->rowCount / $this->tupleCount);
// worth doing -> go
if ($packageSize > 1) {
$this->rowCount = floor($this->rowCount / $packageSize);
$this->conn->query('SET @row:=0;');
$sql = 'SELECT MAX(aggregate.timestamp) AS timestamp,
SUM(aggregate.value) AS value, '.$packageSize.' AS count '.
'FROM ('.
' SELECT timestamp, value, @row:=@row+1 AS row '.
' FROM data WHERE channel_id=?' .
$sqlTimeFilter .
') AS aggregate '.
'GROUP BY row DIV ' . $packageSize .' '.
'ORDER BY timestamp ASC;';
}
}
$stmt = $this->conn->executeQuery($sql, $sqlParameters); //
query for data
return new DataIterator($stmt, $this->rowCount, $this->tupleCount);
}
}
Viele Grüße,
Andreas
More information about the volkszaehler-dev
mailing list