2013-07-03 19 views
7

Próbuję obliczyć liczbę równoczesnych połączeń w czasie wykonywania określonego połączenia, patrząc na zakresy datetime. Moje zapytanie działa, ale zajmuje około 10 minut, aby wykonać tylko 95 000 rekordów, co jest zbyt długie. Wszelkie pomysły na optymalizację?Jednoczesne połączenia

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 

przykładowe dane

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

Jakiej wersji programu SQL Server używasz? –

+1

Używam 2008R2. – user172839

+1

Warunek jest równoważny: 'r_inner.CallStart <= r.CallEnd AND r.CallStart <= r_inner.CallEnd' (przy założeniu, że Start <= Koniec we wszystkich wierszach w obu tabelach.) –

Odpowiedz

1

użycie SQL tak, aby uzyskać listę zdarzeń start/end ...

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

... następnie potraktować to jako prosty sumy biegania problem, który jest różnie rozwiązywany w zależności od twojej wersji SQL Server lub może być łatwo rozwiązany w kodzie, jeśli jest to opcja.

+0

Aby uzyskać liczbę aktywnych połączeń w danym momencie, po prostu dodaj "Where CallStart <@ Time and CallEnd> = @ Time" do każdego zapytania w powyższej UNION - wtedy Sum (CallCount) da ci odpowiednią odpowiedź. – AndyS

3

ten powinien zrobić:

;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 

To powinno potrwać kilka sekund, co najwyżej. Powinien działać na dowolnym SQL Server 2005+.

+0

+1 To jest bardzo szybkie na moich przykładowych danych. Aby zwrócić dokładnie to samo, co zapytanie w OP, wygląda na to, że formuła ma postać '1 + EventCount - TypeCount'. Może jednak twoja formuła jest bardziej rozsądna. Za późno, żeby mi o tym pomyśleć! –

+0

@MartinSmith Tak, wygląda na to, że pierwotne zapytanie jest nieprawidłowe ... – RBarryYoung

+0

Obie nie zwracają oczekiwanych wyników. Czy możesz wyjaśnić, jak próbujesz rozwiązać rozwiązanie, ponieważ nie byłem w stanie odszyfrować zapytania! – user172839