複数の行を1つに結合するアプリケーションをSQL Server 2014データベースに接続しています。アプリケーションの実行中は、このデータベースへの他の接続はありません。
まず、特定の期間内の行のチャンクを選択します。このクエリは、クラスター化ルックアップとマージされた非クラスター化シーク(TIME列)を使用します。
select ...
from FOO
where TIME >= @from and TIME < @to and ...
次に、これらの行をc#で処理し、変更を単一の更新と複数の削除として書き込みます。これは、チャンクごとに何度も発生します。これらも非クラスター化インデックスシークを使用します。
begin tran
update FOO set ...
where NON_CLUSTERED_ID = @id
delete FOO where NON_CLUSTERED_ID in (@id1, @id2, @id3, ...)
commit
これを複数の並列チャンクで実行すると、デッドロックが発生します。 ROWLOCK
とupdate
にdelete
を使用してみましたが、チャンク間にオーバーラップがなくても、何らかの理由で以前より多くのデッドロックが発生しました。
次に、TABLOCKX, HOLDLOCK
update
を使用しますが、select
を並列で実行できないため、並列処理の利点が失われます。
デッドロックを回避しながら複数の並列チャンクを処理する方法はありますか?
この場合、チャンク間に行の重複がない場合、NOLOCK
をselect
で使用しても安全ですか?次にTABLOCKX, HOLDLOCK
は、update
とdelete
のみをブロックしますよね?
または、デッドロックが発生することを受け入れて、アプリケーションでクエリを再試行する必要がありますか?
[〜#〜] update [〜#〜](追加情報):これまでのすべてのデッドロックは、update
およびdelete
フェーズで発生し、 select
。今日、これを解決できない場合は、いくつかのデッドロックログを取得しようとします(以前は正しいトレースフラグが有効にされていませんでした)。
[〜#〜] update [〜#〜]:これらは、ROWLOCK
で発生するデッドロックの2つの配置であり、どちらもdelete
ステートメントのみを参照しますそれが使用する非クラスター化インデックス。これらがテーブルヒントなしで発生したデッドロックと同じであるかどうかは、再現できなかったためわかりません。
.xdlから他に必要なものがあるかどうかを尋ねます。すべてを添付するのは少し疲れています。
このコードの複数のインスタンスが並行して実行されるのを防ぐために、更新トランザクションで sp_getapplock
を使用します。これは、テーブルロックヒントのように選択ステートメントをブロックしません。
ロックの取得にはタイムアウトパラメータよりも長い時間がかかる場合があるため、再試行ロジックをプログラムする必要があります。
これは、更新トランザクションをsp_getapplock
にラップする方法です。
BEGIN TRANSACTION;
BEGIN TRY
DECLARE @VarLockResult int;
EXEC @VarLockResult = sp_getapplock
@Resource = 'some_unique_name_app_lock',
@LockMode = 'Exclusive',
@LockOwner = 'Transaction',
@LockTimeout = 60000,
@DbPrincipal = 'public';
IF @VarLockResult >= 0
BEGIN
-- Acquired the lock
update FOO set ...
where NON_CLUSTERED_ID = @id
delete FOO where NON_CLUSTERED_ID in (@id1, @id2, @id3, ...)
END ELSE BEGIN
-- return some error code, so that the caller could retry
END;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
-- handle the error
END CATCH;
選択ステートメントに変更を加える必要はありません。
チャンク内のIDは重複しないと言っていても、NOLOCK
はお勧めしません。このヒントにより、SELECTクエリは変更されている一部のページをスキップでき、一部のページを2回読み取ることができます。このような動作が許容される可能性はほとんどありません。