2012-04-08 6 views
5

一連の(IP varchar(15)、DateTime datetime2)値を持つテーブルがあります。各行は、ユーザーが作成したHTTP要求に対応しています。私はにこれらの行にセッション番号を割り当てたいと思う。異なるIPアドレスはセッション番号が異なります。最後の要求が30分より古い場合は同じIPに新しいセッション番号を割り当てる必要があります。SQL Server:row_numberはタイムアウトで分割されます

IP,  DateTime,   SessionNumber, RequestNumber 
1.1.1.1, 2012-01-01 00:01, 1,    1 
1.1.1.1, 2012-01-01 00:02, 1,    2 
1.1.1.1, 2012-01-01 00:03, 1,    3 
1.1.1.2, 2012-01-01 00:04, 2,    1 --different IP => new session number 
1.1.1.2, 2012-01-01 00:05, 2,    2 
1.1.1.2, 2012-01-01 00:40, 3,    1 --same IP, but last request 35min ago (> 30min) 

列1と2は入力です.3と4は望ましい出力です。この表は2人のユーザーを示しています。

基礎となるテーブルが本当に大きいので、これはどのように効率的に解決できますか?私はデータ(1つまたは2つ)上のパスの小さな一定量を好むだろう。

+0

どのバージョンのSQL Serverですか? 2012年には、新しい 'OVER'節機能が役立ちます。 –

+0

はい、SQL Server 2012です。 – usr

答えて

8

ここで2,3回の試行があります。

;WITH CTE1 AS 
(
SELECT *, 
IIF(DATEDIFF(MINUTE, 
     LAG(DateTime) OVER (PARTITION BY IP ORDER BY DateTime), 
     DateTime) < 30,0,1) AS SessionFlag 
FROM Sessions 
), CTE2 AS 
(
SELECT *, 
     SUM(SessionFlag) OVER (PARTITION BY IP 
            ORDER BY DateTime) AS IPSessionNumber 
FROM CTE1 
) 
SELECT IP, 
     DateTime, 
     DENSE_RANK() OVER (ORDER BY IP, IPSessionNumber) AS SessionNumber, 
     ROW_NUMBER() OVER (PARTITION BY IP, IPSessionNumber 
           ORDER BY DateTime) AS RequestNumber 
FROM CTE2 

これは、2つのソート操作(IP, IPSessionNumberによって、その後IP, DateTimeによる)を持っていますが、SessionNumberは限り異なるユニークなセッション番号が/ 30分のIPアドレスごとにそれぞれの新しいセッションに割り当てられているとして任意に割り当てることができることを前提としていませんルール。

SessionNumberを時系列順に割り当てます。私は以下を使用しました。

;WITH CTE1 AS 
(
SELECT *, 
IIF(DATEDIFF(MINUTE, 
     LAG(DateTime) OVER (PARTITION BY IP ORDER BY DateTime), 
     DateTime) < 30,0,1) AS SessionFlag 
FROM Sessions 
), CTE2 AS(
SELECT *, 
     SUM(SessionFlag) OVER (ORDER BY DateTime) AS GlobalSessionNo 
FROM CTE1 
), CTE3 AS(
SELECT *, 
     MAX(CASE WHEN SessionFlag = 1 THEN GlobalSessionNo END) 
       OVER (PARTITION BY IP ORDER BY DateTime) AS SessionNumber 
FROM CTE2) 
SELECT IP, 
     DateTime, 
     SessionNumber, 
     ROW_NUMBER() OVER (PARTITION BY SessionNumber 
           ORDER BY DateTime) AS RequestNumber 
FROM CTE3 

これにより、ソート操作の数は4に増えます。

+0

2つのIPのインターリーブからの要求があった場合、そのセッションは混在しませんか? – Andomar

+0

@Andomar - 良い点!一定。 –

+0

ウィンドウ数の使用は独創的です!私はそのトリックを覚えています。 – usr

2

ここでは、テーブル変数とrow_numberを使用して、再帰的なCTEで使用できるIDを作成するバージョンを示します。カーソルと1つのクエリ(Martinが提供)とのパフォーマンスを比較することは、価値があるかもしれません。

CREATE TABLE #T 
(
    IP varchar(15), 
    DateTime datetime, 
    ID int, 
    primary key (IP, ID) 
) 

insert into #T(IP, DateTime, ID) 
select IP, DateTime, row_number() over(partition by IP order by DateTime) 
from #sessionRequests 

;with C as 
(
    select IP, 
     ID, 
     DateTime, 
     1 as Session 
    from #T 
    where ID = 1 
    union all 
    select T.IP, 
     T.ID, 
     T.DateTime, 
     C.Session + case when datediff(minute, C.DateTime, T.DateTime) >= 30 then 1 else 0 end 
    from #T as T 
    inner join C 
     on T.IP = C.IP and 
     T.ID = C.ID + 1 
) 
SELECT IP, 
     DateTime, 
     dense_rank() over(order by IP, Session) as SessionNumber, 
     row_number() over(partition by IP, Session order by DateTime) as RequestNumber 
from C 
order by IP, DateTime, SessionNumber, RequestNumber 
option (maxrecursion 0) 
+1

私はカーソルベースのアプローチのように、拡張が容易なので、このバージョンが好きです。私は、オプティマイザの問題を修正した一時テーブルを使用するように変更しました(テーブル変数には統計がありません)。また、このコードが動作することを確認しました。ありがとう! – usr

関連する問題