MySQL快速检索每组中的最后一条记录
Posted
技术标签:
【中文标题】MySQL快速检索每组中的最后一条记录【英文标题】:MySQL fast retrieve last record in each group 【发布时间】:2019-10-04 19:37:57 【问题描述】:我有一张记录设备 GPS 数据 logs(id - PK AI, device_id - FK, lat - DECIMAL, long - DECIMAL, time - DATETIME)
的表格。 Id 是主键,有一个index on (id, device_id)
,我想获取每个设备的最新记录。
我目前的查询是:
SELECT * FROM devices
WHERE devices.id IN (
SELECT MAX(id) FROM devices GROUP BY device_id
)
在包含 150 万条记录和 5 个唯一设备的表上,查询需要 8 秒。是否可以对其进行优化?这些设备每秒都在发送数据,我预计总共有 2000 台设备。
即使有 5 个设备也太慢了。
我的另一个查询是在一段时间内选择设备的路由。一天的时间也需要 10 秒。
mysql 是该任务的正确选择吗?我应该选择另一个数据库吗?有没有办法让查询更快?
SQL fiddle
【问题讨论】:
见meta.***.com/questions/333952/… 用小提琴编辑 - sqlfiddle.com/#!9/2de1aa/1/0 您需要添加INDEX(device_id, id)
。同时,INDEX(id, device_id)
可能没用。
【参考方案1】:
我会推荐以下内容。首先,将代码改写为:
SELECT d.*
FROM devices d
WHERE d.id = (SELECT MAX(d2.id) FROM devices d2 WHERE d2.device_id = d.device_id);
但首先要在devices(device_id, id)
上创建一个索引。
编辑:
我想知道一些外部优化是否会有所帮助,例如使用datetime
:
SELECT d.*
FROM devices d
WHERE d.datetime >= NOW() - INTERVAL 1 HOUR AND
d.id = (SELECT MAX(d2.id)
FROM devices d2
WHERE d2.device_id = d.device_id AND
d2.datetime >= NOW() - INTERVAL 1 HOUR
);
为此,你还需要devices(datetime, device_id)
上的索引。
【讨论】:
导致超时。查询时间过长 我应该在 (device_id, id) 上创建索引并将索引放在 (id, device_id) 上吗? 索引在 (device_id, id) 上,查询再次超时。 @lam3r4370 。 . .你能从explain
看出索引是否正常工作吗?
它使用的是 device_id 上的 FK 索引。我将其更改为使用 (device_id, id) 上的索引,但它仍然超时【参考方案2】:
尝试这两个查询中的每一个。通常,您的“最大行”查询行中至少有一个对我很有效。
查询 1:
SELECT
d.*
FROM devices d
LEFT OUTER JOIN devices larger_d
ON larger_d.device_id = d.device_id
AND larger_d.id > d.id
WHERE larger_d.device_id IS NULL
查询 2:
SELECT
d.*
FROM devices d
INNER JOIN (
SELECT
MAX(id) AS id,
device_id
FROM devices d
GROUP BY device_id
) largest_d
ON largest_d.device_id = d.device_id
AND largest_d.id = d.id
在这两种情况下,在运行这些查询之前,您都需要在 (device_id,id)
上建立索引。
针对您的 cmets 对其他人的回答,(id,device_id
) 索引与我们建议的索引不同。您不需要删除它,但是它会减慢插入速度(就像所有索引一样)。但是,对于此查询,它没有用处,因此如果您没有特定理由保留它,您可以将其删除。
【讨论】:
第一个超时,但第二个 - WOW - 查询耗时 0.0080 秒! 你能解释一下第二个查询是如何快速运行的吗? 在精确的技术层面上?不,我只是使用它多年,因为它是推荐的查询方式,例如你的:dev.mysql.com/doc/refman/8.0/en/… 大多数情况下,它很快,因为它不慢。使用OR
通常很慢,这就是您的IN
语句在查询中所做的。因此,即使我们的子查询基本相同,我的使用 JOIN
而你的使用 IN
的事实是不同的。我最好的解释是优化器被设计成最适合 JOIN,所以我的查询 2 效果最好。以上是关于MySQL快速检索每组中的最后一条记录的主要内容,如果未能解决你的问题,请参考以下文章