0

何らかの理由で、このクエリを使用して時間間隔にギャップが見られます。基本的なデータを使用するだけで動作するようになりました。ただし、テーブルを結合して WHERE 句を指定すると、時間間隔にギャップが生じます。また、S.SessionEndTime を間隔に組み込んで、ResponseTime と SessionEndTime の間で特定の 1 分間の間隔と重複するレコードの数を見つける必要があります。

これが私が使用しているクエリです。派生テーブルを使用して、1 分間隔の COUNT に基づいて 1 時間あたりの MAX を取得します。

    DECLARE @start_date     DATETIME
DECLARE @end_date       DATETIME
DECLARE @interval TIME

SET @start_date = '08/01/2012'
SET @end_date = '08/01/2012 12:00:00'
SET @interval = '00:01:00.00';

    WITH TimeWindowsCTE AS 
    ( 
        SELECT 
            @start_date AS WindowStart, @start_date + @interval AS WindowEnd 
        UNION ALL 
        SELECT 
            SW.WindowStart + @Interval, SW.WindowEnd + @interval 
        FROM 
            TimeWindowsCTE AS SW 
        WHERE 
            SW.WindowEnd < @end_date 
    ) 
    SELECT 
        DATEADD(hour, DATEDIFF(hour, CONVERT(datetime, '19000101', 112), t1.WindowStart), CONVERT(datetime, '19000101', 112)) WindowStart, 
        MAX([Sessions]) [Sessions]
    FROM 
    (
        SELECT 
            SW.WindowStart, COUNT(*) [Sessions] 
        FROM 
            TimeWindowsCTE AS SW 
            LEFT OUTER JOIN SessionDetails AS S ON SW.WindowStart <= S.ResponseTime and S.ResponseTime < SW.WindowEnd
            --I need to introduce the S.SessionEndTime into the JOIN so I can count the number of records that 
            --fall within the interval
            LEFT OUTER JOIN VoipDetails V on S.SessionIdTime = V.SessionIdTime and S.SessionIdSeq = V.SessionIdSeq                      
            WHERE V.ToGatewayId IS NOT NULL
        GROUP BY 
            SW.WindowStart
    ) t1
    GROUP BY 
        DATEADD(hour, DATEDIFF(hour, CONVERT(datetime, '19000101', 112), t1.WindowStart), CONVERT(datetime, '19000101', 112))
    ORDER BY 
        DATEADD(hour, DATEDIFF(hour, CONVERT(datetime, '19000101', 112), t1.WindowStart), CONVERT(datetime, '19000101', 112))
    OPTION (maxrecursion 0)

ここに私が得ている出力があります

日付セッション
2012-08-01 00:00:00.000 5
2012-08-01 01:00:00.000 3
2012-08-01 02:00:00.000 2
2012-08-01 03:00:00.000 2
2012-08-01 05:00:00.000 1
2012-08-01 06:00:00.000 2
2012-08-01 07:00:00.000 3
2012-08-01 08:00:00.000 2
2012-08-01 09:00:00.000 2
2012-08-01 10:00:00.000 1

04:00:00 の期間に 0 が必要です。私が達成しようとしているのは、その時間に発生した同時セッションの数を特定することであり、正時のセッション数ではありません。ここでオーバーラップの出番です。コールが午前 8 時 56 分に開始され、午前 9 時 26 分に終了した場合、少なくとも午前 8 時に 1 つのコールと午前 9 時に 1 つのコールがあるはずです。次に、1 日の 1 時間ごとの同時セッション数に基づいて、特定の日の MAX を見つけ、それをレポートに使用します。

これは、データの基本構造です。

@Sessions ( SessionIdSeq, ResponseTime, SessionEndTime ) 値に挿入します
    (1, '20120901 00:00:00', '20120901 05:59:59' ), -- 1 回のセッションで数時間。
    (1, '20120901 01:01:00', '20120901 01:01:30' ), -- 重なりの詰め合わせ ...
    (1, '20120901 01:02:00', '20120901 01:03:30' ), -- ... 1 時間のセッション。
    (1, '20120901 00:00:05.077', '20120901 00:04:02.280' ),
    (1, '20120901 00:00:14.687', '20120901 00:06:05.947' ),
    (1, '20120901 00:00:17.857', '20120901 00:07:34.757' ),
    (1, '20120901 00:00:25.843', '20120901 00:07:38.720' ),
    (1, '20120901 00:00:29.427', '20120901 00:01:58.180' ),
    (1, '20120901 00:00:31.853', '20120901 00:05:10.733' ),
    (1, '20120901 00:00:40.693', '20120901 00:00:44.237' ),
    (1, '20120901 00:00:58.773', '20120901 00:06:14.667' ),
    (1, '20120901 00:00:59.457', '20120901 00:01:01.310' ),
    (1, '20120901 00:01:16.390', '20120901 00:11:18.383' )
4

1 に答える 1

0

さて、ここで説明が欠けているのは、次の両方を計算する TSQL です: - 1 時間ごとにアクティブなセッションの合計数と - 1 時間ごとにアクティブな同時セッションの最大数。

編集: 更新された質問のサンプル データが使用され、同時セッションを示す最後のクエリの出力にセッション ID が含まれるようになり、以前の最適化のバグが修正され、パフォーマンスが大幅に向上しました。

注意: これらのクエリは、SessionId値が行ごとに異なる場合に最適に機能します。すべての行にの値を使用する1と、残念な結果になります。したがって、列のIDENTITYプロパティ。SessionId

-- Parameters.
declare @Start as DateTime = '20120901 00:00:00'
declare @End as DateTime = '20120901 12:00:00'
declare @Interval as Time = '01:00:00.00' -- One hour.
select @Start as [Start], @End as [End], @Interval as [Interval]

-- Sample data.
declare @Sessions as Table ( SessionId Int Identity, SessionStart DateTime, SessionEnd DateTime )
insert into @Sessions ( SessionStart, SessionEnd ) values
  ( '20120901 00:00:00', '20120901 05:59:59' ), -- Several hours in a single session.
  ( '20120901 01:01:00', '20120901 01:01:30' ), -- An assortment of overlapping ... 
  ( '20120901 01:02:00', '20120901 01:03:30' ), -- ... sessions during a single hour. 
  ( '20120901 00:00:05.077', '20120901 00:04:02.280' ),
  ( '20120901 00:00:14.687', '20120901 00:06:05.947' ),
  ( '20120901 00:00:17.857', '20120901 00:07:34.757' ),
  ( '20120901 00:00:25.843', '20120901 00:07:38.720' ),
  ( '20120901 00:00:29.427', '20120901 00:01:58.180' ),
  ( '20120901 00:00:31.853', '20120901 00:05:10.733' ),
  ( '20120901 00:00:40.693', '20120901 00:00:44.237' ),
  ( '20120901 00:00:58.773', '20120901 00:06:14.667' ),
  ( '20120901 00:00:59.457', '20120901 00:01:01.310' ),
  ( '20120901 00:01:16.390', '20120901 00:11:18.383' )
select * from @Sessions 

-- Summary of sessions active at any time during each hour. 
; with SampleWindows as ( 
  select @Start as WindowStart, @Start + @Interval as WindowEnd 
  union all 
  select SW.WindowStart + @Interval, SW.WindowEnd + @Interval 
    from SampleWindows as SW 
    where SW.WindowEnd < @End 
  ) 
  select SW.WindowStart, Count( S.SessionStart ) as [Sessions] 
    from SampleWindows as SW left outer join 
      @Sessions as S on SW.WindowStart <= S.SessionEnd and S.SessionStart < SW.WindowEnd 
    group by SW.WindowStart 

-- Summary of maximum concurrent sessions active during each hour. 
; with SampleWindows as ( 
  select 1 as SampleWindowId, @Start as WindowStart, @Start + @Interval as WindowEnd 
  union all 
  select SW.SampleWindowId + 1, SW.WindowStart + @Interval, SW.WindowEnd + @Interval 
    from SampleWindows as SW 
    where SW.WindowEnd < @End 
  ), 
  ActiveSessionsDuringWindow as ( 
  select SW.SampleWindowId, SW.WindowStart, SW.WindowEnd, S.SessionId, S.SessionStart, S.SessionEnd, 
    -- A "pane" is the more restrictive of the window and the session start/end times. 
    case when SW.WindowStart <= S.SessionStart then S.SessionStart else SW.WindowStart end as PaneStart, 
    case when SW.WindowEnd >= S.SessionEnd then S.SessionEnd else SW.WindowEnd end as PaneEnd
    from SampleWindows as SW left outer join 
      @Sessions as S on SW.WindowStart <= S.SessionEnd and S.SessionStart < SW.WindowEnd 
  ), 
  ConcurrentSearch as ( 
  select SampleWindowId, WindowStart, WindowEnd, SessionId, SessionStart, SessionEnd, PaneStart, PaneEnd, 
    Cast( '|' + Right( Replicate( '0', 3 ) + Cast( SessionId as VarChar(4) ), 4 ) + '|' as VarChar(1024) ) as SessionIds, 
    Cast( case when SessionId is NULL then 0 else 1 end as Int ) as Sessions 
    from ActiveSessionsDuringWindow 
  union all 
  select CS.SampleWindowId, CS.WindowStart, CS.WindowEnd, ASDW.SessionId, CS.SessionStart, CS.SessionEnd, 
    case when CS.PaneStart <= ASDW.PaneStart then ASDW.PaneStart else CS.PaneStart end as PaneStart, 
    case when CS.PaneEnd >= ASDW.PaneEnd then ASDW.PaneEnd else CS.PaneEnd end as PaneEnd, 
    Cast( CS.SessionIds + Right( Replicate( '0', 3 ) + Cast( ASDW.SessionId as VarChar(4) ), 4 ) + '|' as VarChar(1024) ), 
    CS.Sessions + 1 
    from ConcurrentSearch as CS inner join 
      ActiveSessionsDuringWindow as ASDW on ASDW.SampleWindowId = CS.SampleWindowId and 
        -- We haven't visited this session along this path. 
        CS.SessionId < ASDW.SessionId and -- EDIT: Reduce the size of the search tree. 
        CharIndex( '|' + Right( Replicate( '0', 3 ) + Cast( ASDW.SessionId as VarChar(4) ), 4 ) + '|', CS.SessionIds ) = 0 and 
        -- The session's pane overlaps the concurrent search pane. 
        CS.PaneStart <= ASDW.PaneEnd and ASDW.PaneStart <= CS.PaneEnd 
  )
  select WindowStart, Max( Sessions ) as Sessions,
    ( select top 1 SessionIds from ConcurrentSearch where Sessions = Max( CS.Sessions ) ) as SessionIds
    from ConcurrentSearch as CS
    group by WindowStart 

@Sessions以下は、テーブルの行 ID 値を使用しない最後のクエリのバリエーションです。代わりにRow_Number()、クエリの実行中に適切な値を割り当てるために使用します。これはまた、SessionId値が 4 桁を超えないという前提を、任意の時間内にアクティブなセッションが 9,999 を超えないという前提に変更します。

-- Summary of maximum concurrent sessions active during each hour.
; with SampleWindows as (  
  select 1 as SampleWindowId, @Start as WindowStart, @Start + @Interval as WindowEnd  
  union all  
  select SW.SampleWindowId + 1, SW.WindowStart + @Interval, SW.WindowEnd + @Interval  
    from SampleWindows as SW  
    where SW.WindowEnd < @End  
  ),  
  ActiveSessionsDuringWindow as (  
  select SW.SampleWindowId, SW.WindowStart, SW.WindowEnd, S.SessionStart, S.SessionEnd,  
    -- A "pane" is the more restrictive of the window and the session start/end times.  
    case when SW.WindowStart <= S.SessionStart then S.SessionStart else SW.WindowStart end as PaneStart,  
    case when SW.WindowEnd >= S.SessionEnd then S.SessionEnd else SW.WindowEnd end as PaneEnd,
    Row_Number() over ( partition by SW.SampleWindowId order by S.SessionStart ) as SampleId
    from SampleWindows as SW left outer join  
      @Sessions as S on SW.WindowStart <= S.SessionEnd and S.SessionStart < SW.WindowEnd  
  ),  
  ConcurrentSearch as (  
  select SampleWindowId, WindowStart, WindowEnd, SampleId, SessionStart, SessionEnd, PaneStart, PaneEnd,  
    Cast( '|' + Right( Replicate( '0', 3 ) + Cast( SampleId as VarChar(4) ), 4 ) + '|' as VarChar(1024) ) as SampleIds,  
    Cast( case when SampleId is NULL then 0 else 1 end as Int ) as Sessions  
    from ActiveSessionsDuringWindow  
  union all  
  select CS.SampleWindowId, CS.WindowStart, CS.WindowEnd, ASDW.SampleId, CS.SessionStart, CS.SessionEnd,  
    case when CS.PaneStart <= ASDW.PaneStart then ASDW.PaneStart else CS.PaneStart end as PaneStart,  
    case when CS.PaneEnd >= ASDW.PaneEnd then ASDW.PaneEnd else CS.PaneEnd end as PaneEnd,  
    Cast( CS.SampleIds + Right( Replicate( '0', 3 ) + Cast( ASDW.SampleId as VarChar(4) ), 4 ) + '|' as VarChar(1024) ),  
    CS.Sessions + 1  
    from ConcurrentSearch as CS inner join  
      ActiveSessionsDuringWindow as ASDW on ASDW.SampleWindowId = CS.SampleWindowId and  
        -- We haven't visited this session along this path.  
        CS.SampleId < ASDW.SampleId and -- EDIT: Reduce the size of the search tree.  
        CharIndex( '|' + Right( Replicate( '0', 3 ) + Cast( ASDW.SampleId as VarChar(4) ), 4 ) + '|', CS.SampleIds ) = 0 and  
        -- The session's pane overlaps the concurrent search pane.  
        CS.PaneStart <= ASDW.PaneEnd and ASDW.PaneStart <= CS.PaneEnd  
  ) 
  select WindowStart, Max( Sessions ) as Sessions
    from ConcurrentSearch as CS 
    group by WindowStart  

これは、既存のテーブルに対して実行するように簡単に変更できるはずです。SessionStart昇順、昇順の単一インデックスにより、SessionEndパフォーマンスが向上するはずです。

于 2012-09-19T23:31:48.883 に答える