我有几百万行的表,需要获取特定ID的最后一行
例如最后一行有device_id = 123而最后一行有device_id = 1234
因为表格太大而且排序需要花费很多时间,所以可以在不排序表的情况下选择最后的200,然后只需订购那些200并获取我需要的行。
我该怎么做?
提前感谢您的帮助!
更新
我的PostgreSQL版本是9.2.1
示例数据:
time device_id data data ....
"2013-03-23 03:58:00-04" | "001EC60018E36" | 66819.59 | 4.203
"2013-03-23 03:59:00-04" | "001EC60018E37" | 64277.22 | 4.234
"2013-03-23 03:59:00-04" | "001EC60018E23" | 46841.75 | 2.141
"2013-03-23 04:00:00-04" | "001EC60018E21" | 69697.38 | 4.906
"2013-03-23 04:00:00-04" | "001EC600192524"| 69452.69 | 2.844
"2013-03-23 04:01:00-04" | "001EC60018E21" | 69697.47 | 5.156
....
所以如果device_id = 001EC60018E21 我想要与device_id最新的行。 这个device_id的最后一行是我想要的行,但它可能是也可能不是表的最后一行。
答案 0 :(得分:2)
就个人而言,我会在device_id
上创建一个综合索引并降序time
:
CREATE INDEX table1_deviceid_time ON table1("device_id","time" DESC);
然后我会使用子查询为每个time
找到最高device_id
,并将子查询结果与device_id
和time
上的主表结合,以找到相关数据,例如:
SELECT t1."device_id", t1."time", t1."data", t1."data1"
FROM Table1 t1
INNER JOIN (
SELECT t1b."device_id", max(t1b."time") FROM Table1 t1b GROUP BY t1b."device_id"
) last_ids("device_id","time")
ON (t1."device_id" = last_ids."device_id"
AND t1."time" = last_ids."time");
请参阅this SQLFiddle。
维护每个设备ID的最高时间戳的基于触发器的物化视图可能会有所帮助。但是,如果多个连接可以插入给定设备ID的数据,则由于连接争用更新锁,这将导致并发问题。如果你不知道什么时候会出现新的设备ID,这也是一种痛苦,因为你必须做一个upsert - 这是非常低效和笨拙的。此外,汇总表创建的额外写入负载和autovacuum工作可能不值得;最好只支付更昂贵的查询的价格。
BTW,time
是列的一个可怕名称,因为它是内置的数据类型名称。如果可以,请使用更合适的东西。
答案 1 :(得分:1)
获取每个device_id的“最后”行的一般方法如下所示。
select *
from Table1
inner join (select device_id, max(time) max_time
from Table1
group by device_id) T2
on Table1.device_id = T2.device_id
and Table1.time = T2.max_time;
在不使用ORDER BY的情况下获取“最后”200个device_id数字并不实用,但目前尚不清楚为什么您可能想要首先执行此操作。如果200是任意数字,那么您可以通过获取基于任意时间的表的子集来获得更好的性能。
select *
from Table1
inner join (select device_id, max(time) max_time
from Table1
where time > '2013-03-23 12:03'
group by device_id) T2
on Table1.device_id = T2.device_id
and Table1.time = T2.max_time;