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