0
我有一个表格,其中包含用户活动的记录,其中涵盖了由开始和结束时间指示的跨度。我正在寻找前一天每单位时间内系统中活动用户的数量。计算从开始和结束时间导出的每分钟会话
最大会话长度是一个小时,并且它们不跨越小时边界。会话可以结束,并在同一分钟内开始新会话。
下面是查询的一个精简版:
with minutes AS (
-- ignore this...it generates a day's worth of timestamps for each minute
-- it's hairy but is what I'm stuck with on redshift
select (dateadd(minute, -row_number() over (order by true), sysdate::date)) as minute
from seed_table limit 1440
),
sessions as (
select sid, ts_start, ts_end
from user_sessions s
where ts_end >= sysdate::date-'1 day'::interval
and ts_start < sysdate::date
)
select m.minute, count(distinct(s.sid))
from minutes m
left join sessions s on s.ts_end >= m.minute and s.ts_start < m.minute+'1 min'::interval
group by 1
我试图避开那个讨厌左连接:
-> XN Nested Loop Left Join DS_BCAST_INNER (cost=6913826151.95..4727012848741.55 rows=410434560 width=166)
Join Filter: (("inner".ts_start < ("outer"."minute" + '00:01:00'::interval)) AND ("inner".ts_end >= "outer"."minute"))
下面是基于戈登·利诺夫的答案是什么,几乎为我工作。当用户的会话在一分钟之内转换时,它就会被计算在内。看起来像正确的方向。原来的查询可能会因为同样的原因而计算在内,但有机会在一分钟内获得不同会话ID的计数来解决这个问题。
select minute, sum(count) over (order by minute rows unbounded preceding) as users
from (
select minute, sum(count) as count
from (
(
select date_trunc('minute', ts_start) as minute, count(*) as count
from sessions
group by 1
) union all (
select date_trunc('minute', ts_end) as minute, - count(*) as count
from sessions
group by 1
)
) s1
group by minute
) s2
order by minute;
为了便于比较,这里有一个小时的数据的时序结果:
- 原始查询时间:81301.345毫秒
- 总和,在查询时间:36242.342毫秒
这几乎得到它。因为窗口函数不是聚合函数,所以Redshift不会让我在外部作用域中分组。我将尝试总结开始和结束时的总和,然后按照常规总和在外部范围逐分钟进行总结。 – systemjack
我通过在计算滚动总和之前捕获每分钟的差异来使其工作。我得到的数字看起来是正确的。太棒了!非常感谢! – systemjack
仍不完全正确。这种方法的缺陷是当用户的会话结束并且新的会话在同一分钟内开始时,这在我的真实数据集中经常是这样。这会导致少量的计数不足。 – systemjack