我有两张 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/