【问题标题】:Optimise SQL Query- sensor readings优化 SQL 查询 - 传感器读数
【发布时间】:2015-02-25 22:21:09
【问题描述】:

我有两张桌子

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

我认为这是我连接子查询的方式。但我不知道如何不使用子查询,或者如何在一个查询中完成整个事情(如果这是一个更多高效路线?)

感谢您的任何建议, 查理

编辑-完成的查询(由下面的答案给出,但 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

非常感谢!

【问题讨论】:

    标签: mysql sql time-series aggregate-functions


    【解决方案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
    

    该查询为您提供readings 表中的id 值列表。这些是每个不同传感器的最新读数的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
    

    【讨论】:

    • 快得多是轻描淡写的说法,因为它现在运行时间为 0.134 秒!谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-10
    • 2014-02-04
    • 2014-11-16
    相关资源
    最近更新 更多