优化SQL查询传感器读数

时间:2014-12-29 18:05:30

标签: mysql sql time-series aggregate-functions

我有两张桌子

Sensorlist
id (int, PK)
alias (varchar)

Readings
sensorid (int)
value (decimal)
date (datetime)
id (bigint, PK)

读数表上有id,sensorid和日期的索引。这是在MYSQL中,在树莓派上运行。

我希望得到一个列表,显示列表中的每个传感器,包括最近的读数以及过去24小时内的最小和最大读数。

我有以下两个查询,我将它们组合成一个数组和显示。我无法弄清楚如何将这两个作为一个查询。第一个查询非常慢。我怎样才能提高效率呢?

这需要27秒才能获得最新的读数:

select distinct s.alias, s.id, a.maxdate, r.value from sensorlist s
inner join
(
SELECT MAX(date) maxDate, sensorid FROM readings GROUP BY sensorid
) a on a.sensorid = s.id
inner join readings r on r.sensorid = s.id and r.date = a.maxdate 
ORDER BY s.alias

查询2获取过去24小时内的最小/最大值,这只需0.3秒:

select distinct s.alias, s.id, max(value) as maxval, min(value) as minval from sensorlist s
 inner join readings r on r.sensorid = s.id where r.date > DATE_SUB(NOW(), INTERVAL 24 HOUR) group by r.sensorid

我认为这是我对子查询进行连接的方式..但是我无法弄清楚如何不使用子查询,或者如何在一个查询中完成整个事情(如果这是更多有效的路线?)

感谢您的任何建议, Charli

编辑 - 完成的查询(由下面的答案给出,但是MYSQL不喜欢'minvalue'这个词,根据答案添加索引)

SELECT sensorlist.id, sensorlist.alias, a.maxval, a.minval, b.value AS lastvalue, b.date as recentdate
  FROM (
          SELECT sensorid, MAX(value) AS maxval, MIN(value) AS minval
            FROM readings
           WHERE date >= NOW() - INTERVAL 24 HOUR
           GROUP BY sensorid
       ) AS a
  JOIN (
select value, sensorid, date
FROM readings
JOIN
(
    SELECT MAX(id) id FROM readings GROUP BY sensorid
) as m on m.id = readings.id
)
AS b ON a.sensorid = b.sensorid
  JOIN sensorlist ON sensorlist.id = a.sensorid

非常感谢!

1 个答案:

答案 0 :(得分:1)

此查询获取最近24小时内每个传感器的最大和最小读数。请注意,没有任何DISTINCT指令; GROUP BY为你做了那件事。

          SELECT sensorid, MAX(value) AS maxvalue, MIN(value) AS minvalue
            FROM readings
           WHERE date >= NOW() - INTERVAL 24 HOUR
           GROUP BY sensorid

如果在readings表上创建以下复合索引,则此查询很可能会大大提升性能:(date,sensorid,value)。这被称为覆盖索引,,你可以在你的搜索引擎上查找它。它允许MySQL使用随机访问准确地跳转到索引中的正确位置,然后按顺序扫描该索引以查找所需的信息。整个查询可以从该索引中得到满足。

现在,让我们添加最新的测量要求。查找每个传感器的最新测量的最简单方法是使用此子查询。我假设你的PK readings.id是一个自动增量字段。

SELECT MAX(id) id, sensorid  FROM sensors GROUP BY sensorid

该查询为您提供id表中readings值的列表。这些是每个不同传感器的最新读数的id值。要对其进行优化,您可以在(sensorid, id)上创建另一个覆盖索引。

现在我们可以将该子查询加入查询的其余部分,并使用这些ID查找最新值。请注意,我们最终得到两个不同的子查询。这是必要的,因为我们需要两种不同的聚合,聚合在不同的标准上。我们还将联合传感器别名用于显示目的。

SELECT sensorlist.id, sensorlist.alias, a.maxvalue, a.minvalue, b.value AS lastvalue
  FROM (
          SELECT sensorid, MAX(value) AS maxvalue, MIN(value) AS minvalue
            FROM readings
           WHERE date >= NOW() - INTERVAL 24 HOUR
           GROUP BY sensorid
       ) AS a
  JOIN (
          SELECT value, sensorid
            FROM sensors
            JOIN (
                   SELECT MAX(id) id FROM sensors GROUP BY sensorid
                 ) AS m ON sensors.id = m.id
       ) AS b ON a.sensorid = b.sensorid
  JOIN sensorlist ON sensorlist.id = a.sensorid

使这个表现良好的技巧是通过使用适当的索引来优化打到读数表的两个子查询。

最后,您可以测试此查询,该查询结合了两个聚合器查询,以查看它是否更快。

SELECT sensorlist.id, sensorlist.alias, a.maxvalue, a.minvalue, b.value AS lastvalue
  FROM (
          SELECT sensorid, MAX(value) AS maxvalue, MIN(value) AS minvalue,
                 MAX(id) AS maxid
            FROM readings
           WHERE date >= NOW() - INTERVAL 24 HOUR
           GROUP BY sensorid
       ) AS a
  JOIN readings AS b on b.id = a.maxid
  JOIN sensorlist ON sensorlist.id = a.sensorid