2016-04-29 20 views
0

開始時刻と終了時刻で示される範囲をカバーするユーザーアクティビティのレコードを持つテーブルがあります。前日の時間単位でシステム内でアクティブなユーザーの数を探しています。開始時刻と終了時刻から派生した1分あたりのセッション数

セッションの最大長は1時間で、時間の境界を超えません。セッションは終了し、新しいセッションは同じ分に開始されます。ここで

は、クエリのストリップダウンバージョンです:

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")) 

はここでほとんどゴードン・リノフの回答に基づいて私のために働いたものです。それは、1分以内にユーザーのセッションが移行するときにカウントされます。しかし、正しい方向のように見えます。元のクエリは同じ理由でカウントされる可能性がありますが、分単位で異なるセッションIDの数を取得する機会はそれを解決します。

  1. 元のクエリ時間:81301.345ミリ秒
  2. 和オーバー問合せ時間:36242.342ミリ秒

答えて

2

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; 

は比較のために、ここではデータの時間の価値のためのタイミング結果です

これは、毎分の開始と停止の回数を数えて累積合計をとることで、これをはるかに高速に実行できます。結果は次のようになります。

select minute, sum(cnt) over (order by minute) 
from ((select date_trunc('minute', ts_start) as minute, count(*) as cnt 
     from sessions 
     group by 1 
    ) union all 
     (select date_trunc('minute', ts_end), - count(*) 
     from sessions 
     group by 1 
    ) 
    ) s 
group by minute 
order by minute; 
+0

これはほぼ完璧です。 Redshiftはウィンドウ関数が集合関数ではないので、外側のスコープで分単位でグループ化させません。私は、開始と終了を合計で分けてみようと思っています。そして、外側の範囲で分単位で定期的に集計します。 – systemjack

+0

私は、ローリングサムを計算する前に、毎分の差をキャプチャすることによって動作するようにしました。私が正しいように見える数字。素晴らしい!どうもありがとうございます! – systemjack

+0

まだ正しくはありません。このアプローチの欠点は、ユーザーのセッションが終了し、新しいセッションが同じ分に開始されたときです。これは実際のデータセットでは頻繁に発生します。この結果、少額の小計が発生します。 @ systemjack。 – systemjack

関連する問題