3

まず、問題の一般的な説明: テーブル内の合計数値を更新する定期的なプロセスを実行しています。問題は、プロセスの実行ごとに複数の更新が必要になる可能性があり、各実行が以前の結果に依存することです。

私の質問は、単一の SQL Server SP で実行できるかということです。

私のコード(サンプルを簡単にするために少し変更しました):

INSERT INTO CustomerMinuteSessions(time, customer, sessions, bytes, previousTotalSessions)
SELECT MS.time,
           MS.customer,
           MS.totalSessions,
           MS.totalBytes,
           CTS.previousTotalSessions
FROM (SELECT time, customer, SUM(sessions) as totalSessions, SUM(bytes) AS totalBytes
      FROM MinuteSessions
      WHERE time > @time
      GROUP BY time, x) MS
CROSS APPLY TVF_GetPreviousCustomerTotalSessions(MS.customer) CTS
ORDER BY time

previousTotalSessions列は の他の行に依存し、UpdatedTableその値はCROSS APPLYingによって取得されますが、SP をそのまま実行すると、SP の実行TVF_GetPreviousCustomerTotalSessionsに追加された行を取得せずに、すべての行が関数によって取得された値を使用します。

完全を期すために、次のTVF_GetPreviousCustomerTotalSessionsとおりです。

FUNCTION [dbo].[TVF_GetCustomerCurrentSessions] 
(   
    @customerId int
)
RETURNS @result TABLE (PreviousNumberOfSessions int)
AS
BEGIN
    INSERT INTO @result
    SELECT TOP 1 (PreviousNumberOfSessions + Opened - Closed) AS PreviousNumberOfSessions
    FROM CustomerMinuteSessions 
    WHERE CustomerId = @customerId 
    ORDER BY time DESC

    IF @@rowcount = 0
        INSERT INTO @result(PreviousNumberOfSessions) VALUES(0)

    RETURN
END

クエリ内の前の行を後続の行に取得するのに最適なものは何ですか?

4

1 に答える 1

0

SQL-2005 以降を使用している場合は、少数の CTE で一度に実行できます。SQL-2000 を使用する場合は、インライン テーブル値関数を使用できます。

個人的には CTE アプローチの方が好きなので、コードを CTE 構文に変換した概略図を含めます。(念のため、確認用のテスト セットを用意していませんでした)。

WITH LastSessionByCustomer AS  
(
    SELECT CustomerID, MAX(Time)
    FROM CustomerMinuteSessions
    GROUP BY CustomerID
)
, GetPreviousCustomerTotalSessions AS
(
    SELECT LastSession.CustomerID, LastSession.PreviousNumberOfSessions + LastSession.Opened - LastSession.Closed AS PreviousNumberOfSessions
    FROM CustomerMinuteSessions LastSession
    INNER JOIN LastSessionByCustomer ON LastSessionByCustomer.CustomerID = LastSession.CustomerID
)
, MS AS
(
    SELECT time, customer, SUM(sessions) as totalSessions, SUM(bytes) AS totalBytes
    FROM MinuteSessions
    WHERE time > @time
    GROUP BY time, x
)
INSERT INTO CustomerMinuteSessions(time, customer, sessions, bytes, previousTotalSessions)
SELECT MS.time,
           MS.customer,
           MS.totalSessions,
           MS.totalBytes,
           ISNULL(GetPreviousCustomerTotalSessions.previousTotalSessions, 0)
FROM MS 
RIGHT JOIN GetPreviousCustomerTotalSessions ON MS.Customer = GetPreviousCustomerTotalSessions.CustomerID

あなたの質問を少し超えて、テーブル CustomerMinuteSessions データベースが大きくなると、クロス適用を使用したクエリがデータベースに大きな損害を与える可能性があると思います。Index-Seek を取得する可能性を高めるために、次のようなインデックスを追加します。

CREATE INDEX IX_CustomerMinuteSessions_CustomerId
    ON CustomerMinuteSessions (CustomerId, [time] DESC, PreviousNumberOfSessions, Opened, Closed ); 
于 2013-07-03T13:13:14.923 に答える