Skip to content

Commit

Permalink
Fix perf regression introduced with #335
Browse files Browse the repository at this point in the history
  • Loading branch information
andig committed Oct 9, 2015
1 parent 14fe309 commit c94d49e
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 19 deletions.
16 changes: 13 additions & 3 deletions lib/Interpreter/Interpreter.php
Expand Up @@ -171,13 +171,23 @@ 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);
$sql = 'SELECT MAX(timestamp) FROM data WHERE channel_id=? AND timestamp < (SELECT MAX(timestamp) FROM data WHERE channel_id=? AND timestamp<?)';
// $sql = 'SELECT IFNULL(' .
// 'SELECT MAX(timestamp) FROM data WHERE channel_id=? AND timestamp < (SELECT MAX(timestamp) FROM data WHERE channel_id=? AND timestamp<?), ' .
// 'SELECT MAX(timestamp) FROM data WHERE channel_id=? AND timestamp<?' .
// ')';

// if not second-highest timestamp take highest before $this->from
if (null === $from = $this->conn->fetchColumn($sql, array($this->channel->getId(), $this->channel->getId(), $this->from), 0)) {
$sql = 'SELECT MAX(timestamp) FROM data WHERE channel_id=? AND timestamp<?';
$from = $this->conn->fetchColumn($sql, array($this->channel->getId(), $this->from), 0);
}

if ($from)
$this->from = (double)$from; // bigint conversion
}
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';
$sql = 'SELECT MIN(timestamp) FROM data WHERE channel_id=? AND timestamp>?';
$to = $this->conn->fetchColumn($sql, array($this->channel->getId(), $this->to), 0);
if ($to)
$this->to = (double)$to; // bigint conversion
Expand Down
39 changes: 23 additions & 16 deletions lib/Interpreter/SQL/MySQLAggregateOptimizer.php
Expand Up @@ -80,10 +80,11 @@ private function validateAggregationUsage() {
if ($this->aggValid === null) {
$this->aggValid = false;

$aggregationLevel = $this->aggregator->getOptimalAggregationLevel($this->channel->getUuid(), $this->groupBy);
if ($aggregationLevel) {
$aggregationLevels = $this->aggregator->getOptimalAggregationLevel($this->channel->getUuid(), $this->groupBy);

if ($aggregationLevels) {
// choose highest level
$this->aggLevel = $aggregationLevel[0]['level'];
$this->aggLevel = $aggregationLevels[0]['level'];

// numeric value of desired aggregation level
$this->aggType = Util\Aggregation::getAggregationLevelTypeValue($this->aggLevel);
Expand Down Expand Up @@ -238,24 +239,29 @@ private function getAggregationBoundary($aggFromDelta = null) {
$dateFormat = Util\Aggregation::getAggregationDateFormat($this->aggLevel); // day = "%Y-%m-%d"

// aggFrom becomes beginning of first period with aggregate data
// find 'left' border of aggregate table after $from
$sqlParameters = array($this->channel->getId(), $this->aggType, $this->from);
if (isset($aggFromDelta)) {
// shift 'left' border of aggregate table use by $aggFromDelta units
// shift 'left' border of aggregate table by $aggFromDelta units (used to spare 1 tuple)
$sql = 'SELECT UNIX_TIMESTAMP(' .
'DATE_ADD(' .
'FROM_UNIXTIME(MIN(timestamp) / 1000, ' . $dateFormat . '), ' .
'INTERVAL ' . $aggFromDelta . ' ' . $this->aggLevel .
')) * 1000 ' .
'FROM aggregate WHERE channel_id=? AND type=? AND ' .
' UNIX_TIMESTAMP(FROM_UNIXTIME(timestamp / 1000, ' . $dateFormat . ')) * 1000 >=?';
')) * 1000 ';
}
else {
// find 'left' border of aggregate table after $from
$sql = 'SELECT UNIX_TIMESTAMP(FROM_UNIXTIME(MIN(timestamp) / 1000, ' . $dateFormat . ')) * 1000 ' .
'FROM aggregate WHERE channel_id=? AND type=? AND ' .
' UNIX_TIMESTAMP(FROM_UNIXTIME(timestamp / 1000, ' . $dateFormat . ')) * 1000 >=?';
$sql = 'SELECT UNIX_TIMESTAMP(FROM_UNIXTIME(MIN(timestamp) / 1000, ' . $dateFormat . ')) * 1000 ';
}
$this->aggFrom = (float) $this->conn->fetchColumn($sql, $sqlParameters, 0);

$sql .= 'FROM aggregate WHERE channel_id=? AND type=? AND ' .
'timestamp >= UNIX_TIMESTAMP(' .
'DATE_ADD(' .
'FROM_UNIXTIME(? / 1000, ' . $dateFormat . '), ' .
'INTERVAL 1 ' . $this->aggLevel .
')' .
') * 1000';

$this->aggFrom = (double) $this->conn->fetchColumn($sql, $sqlParameters, 0);
$this->aggTo = null;

// aggregate table contains relevant data?
Expand All @@ -272,25 +278,26 @@ private function getAggregationBoundary($aggFromDelta = null) {
$sqlParameters[] = $this->to;
$sql .= ' AND timestamp<?';
}
$this->aggTo = (float) $this->conn->fetchColumn($sql, $sqlParameters, 0);
$this->aggTo = (double) $this->conn->fetchColumn($sql, $sqlParameters, 0);
}

if (self::$debug) {
printf("from .. aggFrom .. aggTo .. to\n");
printf("%s |%s .. %s| %s\n", self::pd($this->from), self::pd($this->aggFrom), self::pd($this->aggFrom), self::pd($this->to));
printf("%s |%s .. %s| %s\n", self::pd($this->from), self::pd($this->aggFrom), self::pd($this->aggTo), self::pd($this->to));
}

return isset($this->aggFrom) && isset($this->aggTo) &&
$this->aggFrom < $this->aggTo &&
$this->from <= $this->aggFrom && $this->aggTo <= $this->to;
$this->from <= $this->aggFrom &&
($this->to === null || $this->to >= $this->aggTo);
}

/**
* Print formatted date
*/
private static function pd($ts) {
$date = \DateTime::createFromFormat('U', (int)($ts/1000))->setTimeZone(new \DateTimeZone('Europe/Berlin'));
return $date->format('d.m.Y H:i:s');
return (null === $ts) ? 'NULL ' : $date->format('d.m.Y H:i:s');
}

/**
Expand Down

0 comments on commit c94d49e

Please sign in to comment.