Select 设备 table 中每个设备的数据 table 的最后一条记录

Select last record from data table for each device in devices table

我对 postgres 数据库的 sql 查询的执行速度有问题。

我有 2 个 tables:

table 1: DEVICES

ID | NAME
------------------
1  | first device
2  | second device

table 2: DATA

ID | DEVICE_ID | TIME                | DATA
--------------------------------------------
1  | 1         | 2016-07-14 2:00:00  | data1
2  | 1         | 2016-07-14 1:00:00  | data2
3  | 2         | 2016-07-14 4:00:00  | data3
4  | 1         | 2016-07-14 3:00:00  | data4
5  | 2         | 2016-07-14 6:00:00  | data5
6  | 2         | 2016-07-14 5:00:00  | data6

我需要得到这个 select 的结果 table:

ID | DEVICE_ID | TIME               | DATA
-------------------------------------------
4  | 1         | 2016-07-14 3:00:00 | data4
5  | 2         | 2016-07-14 6:00:00 | data5

即对于设备中的每个设备 table 我只需要获取一个具有最后 TIME 值的数据记录。

这是我的 sql 查询:

SELECT * FROM db.data d 
    WHERE d.time = (
        SELECT MAX(d2.time) FROM db.data d2 
             WHERE d2.device_id = d.device_id);

这是等效的 HQL 查询:

SELECT d FROM Data d 
    WHERE d.time = (
        SELECT MAX(d2.time) FROM Data d2 
            WHERE d2.device.id = t2.device.id)

是的,我在我的项目中使用 Hibernate ORM - 可能此信息对某些人有用。

我的查询得到了正确答案,但它太长了 - 数据 table 中的 10k 条记录大约需要 5-10 秒,而设备 table 中只有 2 个设备。太可怕了。

首先,我认为问题出在 Hibernate 中。但是 linux 终端中来自 psql 的本机 sql 查询与通过休眠执行的时间相同。

如何优化我的查询?此查询太复杂:

 O(device_count * data_count^2)

由于您使用的是 Postgres,您可以使用 window functions 来实现这一点,如下所示:

select
    sq.id,
    sq.device_id,
    sq.time,
    sq.data
from (
    select
        data.*,
        row_number() over (partition by data.device_id order by data.time desc) as rnk
    from
        data
) sq
where
    sq.rnk = 1

row_number() window 函数首先根据 device_idtime 列对 data table 中的行进行排名,然后外部查询选择排名最高的行。