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_id
和 time
列对 data
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_id
和 time
列对 data
table 中的行进行排名,然后外部查询选择排名最高的行。