2013-07-03 7 views
7

Я пытаюсь вычислить количество одновременных вызовов в тот момент, когда конкретный вызов выполняется, просматривая диапазоны дат-времени. Мой запрос работает, но требуется ~ 10 минут, чтобы выполнить только 95 000 записей, что слишком велико. Любые идеи для оптимизации?Одновременные вызовы

SELECT r.*, 
     rr.ChannelsActive 'ChannelsActive' 
FROM #rg r 
OUTER APPLY 
(
     SELECT SUM(1) AS ChannelsActive 
     FROM #rg r_inner 
     WHERE 
     (
      r_inner.CallStart BETWEEN r.CallStart AND r.CallEnd 
      OR r_inner.CallEnd BETWEEN r.CallStart AND r.CallEnd 
      OR r.CallStart BETWEEN r_inner.CallStart AND r_inner.CallEnd 
      OR r.CallEnd BETWEEN r_inner.CallStart AND r_inner.CallEnd 

    ) 
) rr 

Пример данных

CREATE TABLE #rg 
    (
    CallStart DATETIME, 
    CallEnd DATETIME 
) 

CREATE INDEX ix1 
    ON #rg(CallStart, CallEnd) 

CREATE INDEX ix2 
    ON #rg(CallEnd, CallStart); 

WITH T(N, R) 
    AS (SELECT TOP (95000) ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS RN, 
          ABS(120 + 30 * SQRT(-2 * LOG(ABS(CAST(CAST(CRYPT_GEN_RANDOM(8) AS BIGINT) AS FLOAT)/9223372036854775807))) * COS(2 * PI() * ABS(CAST(CAST(CRYPT_GEN_RANDOM(8) AS BIGINT) AS FLOAT)/9223372036854775807))) 
     FROM sys.all_objects o1, 
       sys.all_objects o2) 
INSERT INTO #rg 
SELECT DATEADD(SECOND, N, GETDATE()), 
     DATEADD(SECOND, N + R, GETDATE()) 
FROM T 
+0

Какую версию SQL Server вы используете? –

+1

Я использую 2008R2. – user172839

+1

Условие эквивалентно: 'r_inner.CallStart <= r.CallEnd AND r.CallStart <= r_inner.CallEnd' (при условии, что Start <= Конец во всех строках в обеих таблицах.) –

ответ

1

Использование SQL, как это, чтобы получить список старт/конечных событий ...

Select CallStart, 1 As CallCount From #rg 
Union All 
Select CallEnd, -1 From #rg 
Order By CallStart 

... потом рассматривать это как простое погонных итоги проблема, которая решается по-разному в зависимости от вашей версии SQL Server или может быть легко устранена в коде, если это вариант.

+0

Чтобы получить количество активных вызовов в любой момент времени, просто добавьте «Where CallStart <@Time And CallEnd> = @Time» к каждому запросу в вышеупомянутом UNION - тогда Sum (CallCount) предоставит вам ответ, который вы хотите. – AndyS

3

Это следует сделать это:

;WITH cteCallEvents As 
(
     SELECT *, CallStart As EventTime, 1 As EventType FROM #rg r 
    UNION ALL 
     SELECT *, CallEnd As EventTime, 0 As EventType FROM #rg r 
) 
, cteCallCounts As 
(
    SELECT *, 
     ROW_NUMBER() OVER(Order By EventTime) as EventCount, 
     ROW_NUMBER() OVER(Partition By EventType Order By EventTime) as TypeCount 
    FROM cteCallEvents 
) 
SELECT *, 
    2*TypeCount - EventCount As OpenCalls 
FROM cteCallCounts 
WHERE EventType = 1 

Это займет пару секунд максимум. Должен работать на любом SQL Server 2005+.

+0

+1 Это очень быстро по моим данным примера. Чтобы вернуть точно так же, как запрос в OP, похоже, что формула будет '1 + EventCount - TypeCount'. Может быть, ваша формула более разумна. Слишком поздно, чтобы я подумал об этом! –

+0

@MartinSmith Да, похоже, что исходный запрос неверен ... – RBarryYoung

+0

Оба не возвращают ожидаемые результаты. Не могли бы вы объяснить, как вы пытаетесь решить решение, поскольку я еще не смог расшифровать запрос? – user172839

Смежные вопросы