mysql - 优化 SQL 查询-传感器读数

标签 mysql sql time-series aggregate-functions

我有两张 table

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

非常感谢!

最佳答案

此查询获取最近 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 使用随机访问准确地跳转到索引中的正确位置,然后按顺序扫描该索引以查找它需要的信息。可以从该索引满足整个查询。

现在,让我们添加 latest-measurement 要求。查找每个传感器的最新测量值的最简单方法是使用此子查询。我假设您的主键 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

关于mysql - 优化 SQL 查询-传感器读数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27693816/

相关文章:

R 使用 data.table 中的条件查找波高于给定值的频率和持续时间

python - 有什么快速方法可以使用 pandas 获得时间序列数据的正确聚合输出?

mysql - 如何选择列中已存在的值

mysql - str_to_date 的奇怪行为,可能会混合表吗?

java - 如何使用 JPA 以编程方式创建长度有限的 MySQL 索引?

mysql - 在sql中设置总和的小数位

python - scikit-learn:cross_val_predict 仅适用于分区

mysql - 在 Windows 中安装 perl DBI-mysql 的问题

sql - SQLITE3 中的跨表更新

java - 为什么 Calendar.setTimeZone() 不会影响从数据库检索的日期