【发布时间】:2019-09-18 17:59:26
【问题描述】:
我有一个查询,它返回一些带有设备 ID 和时间戳的设备状态信息。我正在尝试做一些每日报告,为此我需要知道白天有哪些状态设备。因此,例如,我的查询可能会得到这样的结果
device id start end state
---------------------------------------------------------
1 2017-01-01 13:38 2017-01-03 12:47 1
2 2017-01-01 03:15 2017-01-02 11:04 1
... more records for devices including devices 1 and 2 ...
我想要的结果是
device id start end state
---------------------------------------------------------
1 2017-01-01 13:38 2017-01-01 23:59 1
1 2017-01-02 00:00 2017-01-02 23:59 1
1 2017-01-03 00:00 2017-01-03 12:47 1
2 2017-01-01 03:15 2017-01-01 23:59 1
2 2017-01-02 00:00 2017-01-02 11:04 1
我试过的,是这样的
select
l.device_id,
gs.ts as "day",
case when l.start < gs.ts then gs.ts else l.start end as start,
case when l.end > gs.ts + '1 day'::interval then gs.ts + '1 day'::interval else l.end end as end,
l.state
from ( ... my query goes here ... ) as l
right join
(select generate_series(
date 'start date',
date 'end date',
'1 day'::interval)) as gs(ts)
on ((gs.ts, gs.ts + '1 day'::interval) overlaps (l.start, l.end))
order by l.device_id, l.start
本质上,我使用重叠函数正确加入一系列天,因此与该天重叠的每个间隔都会生成一行,然后我在日期边界处切割间隔。
然后我将其用作我日常计算的嵌套选择。
这种方法的问题在于,正确的连接会生成大量记录,然后连接过滤器会永远占用。这是explain analyze输出的一段
-> Nested Loop Left Join (cost=5371.28..3149290.69 rows=11525332 width=32) (actual time=228.799..32849.000 rows=41197 loops=1)
Join Filter: ... the generate sequence stuff removed for brevity...
Rows Removed by Join Filter: 4994476
如您所见,它生成了大约 500 万行,将它们过滤到 41K 行,操作耗时约 32 秒。
这个问题有更有效的解决方案吗?
【问题讨论】:
标签: sql postgresql