1

レコードがテーブルから削除されないことを除いて、キューのように機能するテーブルがあります。私が試みているのは、現在フロント エンド アプリケーションから処理されていない単一のレコードをストアド プロシージャに返させることです。これを示すために設定した「ロック済み」列があります。これを行っている理由は、一度に 1 人のコール センター エージェントだけがレコードを処理できるようにするためです。これが私のSQLがこれまでにどのように見えるかです。問題は、このクエリを 2 つの別々のセッションから実行した場合 (2 番目のセッションが waitfor ステートメントをコメントアウトした場合)、2 番目のセッションが 10 秒間レコードを返さないことです。レコードを選択する際の order by 句に絞り込みました。オーダーバイを削除すると返されますが、オーダーバイが必要です。

それとも、私のクエリが完全に間違っているのでしょうか? トランザクション分離レベル (シリアル化可能、スナップショット) を使用する必要がありますか?? どんなガイダンスも素晴らしいでしょう!

DECLARE @WorkItemId INT;

BEGIN TRANSACTION

/* TODO: Skip Records That Have Been Completed. */
SET @WorkItemId = (SELECT TOP 1 CampaignSetDetailId FROM CampaignSetDetail WITH (XLOCK, READPAST) WHERE LockedBy IS NULL ORDER BY NEWID(), NumAttempts ASC);

/* */
UPDATE CampaignSetDetail SET LockedBy = 'MPAUL', LockedDTM = GETUTCDATE() WHERE CampaignSetDetailId = @WorkItemId;

/* */
SELECT * FROM CampaignSetDetail WHERE CampaignSetDetailId = @WorkItemId;

WAITFOR DELAY '00:00:10';

COMMIT TRANSACTION
4

3 に答える 3

0

1つのステートメントでそれを行うことができます

DECLARE @WorkItemId INT;

UPDATE [CampaignSetDetail]
    SET
            [LockedBy] = 'MPAUL',
            [LockedDTM] = GETUTCDATE()
    WHERE
            [CampaignSetDetailId] = (
                SELECT TOP 1
                            [CampaignSetDetailId],
                            @WorkItemId = [CampaignSetDetailId]
                    FROM
                            [CampaignSetDetail]
                    WHERE
                            [LockedBy] IS NULL
                    ORDER BY
                            [NumAttempts]);

SELECT
            * -- You shouldn't do this.
    FROM
            [CampaignSetDetail]
    WHERE
            [CampaignSetDetailId] = @WorkItemId;

[CampaignSetDetailId]テーブルにクラスター化インデックスを形成すると仮定しています。次のようなインデックスを考えることができます。

CREATE INDEX [IX_CampaignSetDetail_NumAttempts]
    ON [CampaignSetDetail]([NumAttempts])
    WHERE [LockedBy] IS NULL;

この操作を最適化します。

于 2015-01-16T16:07:51.050 に答える