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

时间:2019-10-04 19:37:57

标签: mysql sql database logging query-optimization

我有一张桌子,上面有设备的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

2 个答案:

答案 0 :(得分:2)

我建议以下内容。首先,将代码重写为:

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)上建立索引。

答案 1 :(得分:1)

尝试这两个查询中的每一个。通常,您的“最大行”查询行中至少有一个对我有效。

查询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)上建立索引。

为回应您对其他人的回答的评论,(id,device_id)索引与我们建议的索引不同。您无需删除它,但是它会降低插入速度(就像所有索引一样)。但是,对于该查询而言,它没有用,因此,如果没有特定原因保留它,则可以将其删除。