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快速检索每组中的最后一条记录的主要内容,如果未能解决你的问题,请参考以下文章

检索每个组中的最后一条记录 - MySQL

检索每个组中的最后一条记录 - MySQL

检索每个组中的最后一条记录 - MySQL

检索每个组中的最后一条记录 - MySQL

检索每个组中的最后一条记录 - MySQL

检索每个组中的最后一条记录 - MySQL