从设备表中的每个设备的数据表中选择最后一条记录

时间:2016-07-21 09:34:33

标签: sql postgresql select greatest-n-per-group

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

我有两张桌子:

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

我需要获取此选择的结果表:

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

即。对于设备表中的每个设备,我只需要获得一个具有最后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 - 这个信息可能对某人有用。

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

首先,我认为问题出在Hibernate中。但是linux终端中psql的本机sql查询与hibernate同时执行。

如何优化查询?此查询过于复杂:

 O(device_count * data_count^2)

1 个答案:

答案 0 :(得分: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()窗口函数首先根据datadevice_id列对time表中的行进行排名,然后外部查询选择最高 - 排行。