我有以下 SQL 查询
SELECT *
FROM `sensor_data` AS `sd1`
WHERE (sd1.timestamp BETWEEN '2017-05-13 00:00:00'
AND '2017-05-14 00:00:00')
AND (`id` =
(
SELECT `id`
FROM `sensor_data` AS `sd2`
WHERE sd1.mid = sd2.mid
AND sd1.sid = sd2.sid
ORDER BY `value` DESC, `id` DESC
LIMIT 1)
)
背景:
我已经 checked the validity of the query通过将 LIMIT 1
更改为 LIMIT 0
,查询工作没有任何问题。但是,对于 LIMIT 1
,查询没有完成,它只是说明 loading
,直到我关闭并重新启动。
分解查询:
我已将具有日期边界的查询分解如下:
SELECT *
FROM `sensor_data` AS `sd1`
WHERE (sd1.timestamp BETWEEN '2017-05-13 00:00:00'
AND '2017-05-14 00:00:00')
这需要大约 0.24 秒来返回包含 8200 行的查询,每行有 5 列。
问题:
我怀疑我的查询的后半部分不正确或未优化。 表格如下:
当前表:
+------+-------+-------+-----+-----------------------+
| id | mid | sid | v | timestamp |
+------+-------+-------+-----+-----------------------+
| 51 | 10 | 1 | 40 | 2015-05-13 11:56:01 |
| 52 | 10 | 2 | 39 | 2015-05-13 11:56:25 |
| 53 | 10 | 2 | 40 | 2015-05-13 11:56:42 |
| 54 | 10 | 2 | 40 | 2015-05-13 11:56:45 |
| 55 | 10 | 2 | 40 | 2015-05-13 11:57:01 |
| 56 | 11 | 1 | 50 | 2015-05-13 11:57:52 |
| 57 | 11 | 2 | 18 | 2015-05-13 11:58:41 |
| 58 | 11 | 2 | 19 | 2015-05-13 11:58:59 |
| 59 | 11 | 3 | 58 | 2015-05-13 11:59:01 |
| 60 | 11 | 3 | 65 | 2015-05-13 11:59:29 |
+------+-------+-------+-----+-----------------------+
问:如何为每个 mid
获取每个 sid
的 MAX(v)
?
NB#1: 在上面的例子中 ROW
53
, 54
, 55
具有相同的值 (40
),但我想检索具有最新时间戳的行,即 ROW
55
。
预期输出:
+------+-------+-------+-----+-----------------------+
| id | mid | sid | v | timestamp |
+------+-------+-------+-----+-----------------------+
| 51 | 10 | 1 | 40 | 2015-05-13 11:56:01 |
| 55 | 10 | 2 | 40 | 2015-05-13 11:57:01 |
| 56 | 11 | 1 | 50 | 2015-05-13 11:57:52 |
| 58 | 11 | 2 | 19 | 2015-05-13 11:58:59 |
| 60 | 11 | 3 | 65 | 2015-05-13 11:59:29 |
+------+-------+-------+-----+-----------------------+
表的结构:
注意#2: 由于此表有超过 1.1 亿个条目,因此设置日期界限非常重要,这限制了 24 小时内约 8000 个条目。
最佳答案
查询可以这样写:
SELECT t1.id, t1.mid, t1.sid, t1.v, t1.ts
FROM yourtable t1
INNER JOIN (
SELECT mid, sid, MAX(v) as v
FROM yourtable
WHERE ts BETWEEN '2015-05-13 00:00:00' AND '2015-05-14 00:00:00'
GROUP BY mid, sid
) t2
ON t1.mid = t2.mid
AND t1.sid = t2.sid
AND t1.v = t2.v
INNER JOIN (
SELECT mid, sid, v, MAX(ts) as ts
FROM yourtable
WHERE ts BETWEEN '2015-05-13 00:00:00' AND '2015-05-14 00:00:00'
GROUP BY mid, sid, v
) t3
ON t1.mid = t3.mid
AND t1.sid = t3.sid
AND t1.v = t3.v
AND t1.ts = t3.ts;
编辑和解释:
第一个子查询(第一个 INNER JOIN
)根据 (mid, sid)
组合获取 MAX(v)
。第二个子查询是为每个 (mid, sid, v)
识别 MAX(ts)
。此时,两个查询不会影响彼此的结果。同样重要的是要注意 ts
日期范围选择是在两个子查询中独立完成的,因此最终查询要检查的行更少,并且没有额外的 WHERE
过滤器申请。
实际上,这转化为最初为每个 (mid, sid)
组合获取 MAX(v)
(第一个子查询);如果对于给定的 (mid, sid)
组合,有多个具有相同值 MAX(v)
的记录,则通过选择MAX(ts)
对于第二个子查询获得的每个 (mid, sid, v)
组合。然后,我们通过两个 INNER JOIN
条件简单地将两个查询的输出相关联,以获取所需记录的 id
。
关于mysql - 使用单个 MySQL 表的各种条件优化 SQL 查询以获得最大值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43990650/