web-dev-qa-db-ja.com

トランザクション(プロセスID)は、別のプロセスを使用してロックリソースでデッドロックされ、デッドロックの犠牲者として選択されました。トランザクションを再実行します

ストアドプロシージャを使用してSQL Server(2008)テーブルにデータを挿入するC#アプリケーションがあります。私はこれを行うためにマルチスレッドを使用しています。ストアドプロシージャがスレッド内から呼び出されています。現在、私のストアドプロシージャは、データの挿入中に「tablock」を使用しています。このコードを実行すると、「トランザクション(プロセスID)が別のプロセスのロックリソースでデッドロックされ、デッドロックの犠牲者として選択されました。トランザクションを再実行してください。」というエラーが発生します。

誰かがこれの解決策を手伝ってくれませんか?

19
user1018213

これは、2つのSQL Serverプロセスが同じリソースにアクセスしているが、順序が異なる場合に発生します。したがって、どちらもデッドロックである他のプロセスを待つことになります。

これを防ぐ方法はいくつかあります。

  • 不要なロックを取得しないでください。クエリに必要なトランザクション分離レベルを確認し、必要に応じてクエリにwith (nolock)ロックヒントを使用します。
  • ロックを取得するときは、各クエリで同じ順序でオブジェクトをロックしてください。

例えば。 Proc1がtable1をロックしてからtable2をロックし、Proc2がtable2をロックしてからtable1をロックすると、問題が発生する可能性があります。この問題を回避するために、どちらかのプロシージャを書き換えて同じ順序でロックを取得できます。

14
Ben

クエリをTRY CATCHブロックにカプセル化し、エラー番号(ロックに関連する)をキャッチできます。

  1. 1204
  2. 1205
  3. 1222

次に、特定の数まで再試行を自動化できます。したがって、次のようなことを行います。

         DECLARE @RetryNo Int = 1
     ,@RetryMaxNo Int = 5;
   WHILE @RetryNo < @RetryMaxNo
      BEGIN
         BEGIN TRY 

         -- put your query that generates locks here....

            SELECT   @RetryNo = @RetryMaxNo;
         END TRY
         BEGIN CATCH
            IF ERROR_NUMBER() IN (1204, 1205, 1222)
               BEGIN
                  SET @RetryNo += 1;
                  -- it will wait for 10 seconds to do another attempt
                  WAITFOR DELAY '00:00:10';
               END 
            ELSE
               THROW;
         END CATCH
      END 

[〜#〜] updlock [〜#〜] などのテーブルヒントを使用することもできます。

6
Mez

更新または挿入するフィールドを確認してください。このフィールドには非クラスター化インデックスがあります。利用できない場合は、最初にこのテーブルにこのフィールドの非クラスター化インデックスを作成し、作成後に以下の手順に従います。

  • テーブルを右クリックして、プロパティを選択します。

  • プロパティの右側のパネルでオプションを選択します。

  • [ロック]タブで、[ページロックを許可]を[False]にし、[行ロックを許可]を[True]にして、[OK]を押します。

  • [新しいクエリ]ボタンを押して、コマンド 'update statistics tablename'を記述して実行します
  • 非クラスター化インデックスを再構築します。
0
Jairath

これはS Kumar DubeyによるMSDNのソリューションです

https://social.msdn.Microsoft.com/Forums/sqlserver/en-US/171d9fa9-0a39-48ce-bc38-35623e0c1075/how-can-i-release-lock-on-tables?forum= transactsql

SPの実行:SP_LOCK結果で、SPID、DBID、OBJID、INDID、TYPE、RESOURCE、MODE、STATUSを取得します。ステータス列を確認します。待機が表示されている場合は、そのSPIDを強制終了します。特定のSPIDを強制終了するにはSPを実行します:65を強制終了します(65はSPIDです)。

この問題を解決するには、SQLサーバー管理者である必要があります。

0
Decula

Lockオブジェクトから使用できます

     static object _lock = new object();
    public static void _main()
    {
            lock (_lock)
            {
                _bulkcopy(myData);
            }
    }
    public static void _bulkcopy(DataTable dt)
    {
        try
        {
            using (var connection = new SqlConnection(ConfigurationSettings.AppSettings.Get("DBConnection")))
            {
                connection.Open();
                SqlTransaction transaction = connection.BeginTransaction();

                using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
                {
                    bulkCopy.BatchSize = 100;
                    bulkCopy.DestinationTableName = "dbo.MyTable";
                    try
                    {
                        bulkCopy.WriteToServer(dt);
                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                        connection.Close();
                    }
                }

                transaction.Commit();
            }




        }
        catch { }
    }
0
xfar

デッドロックのリスクを最小限に抑える方法でデータベースモジュールを設計する必要があります。これを行う方法に関するいくつかの役立つヒントを次に示します。アプリケーションがすべての共有オブジェクトに同じ順序でアクセスすることを確認します。

ここで詳細を確認し、デッドロックを回避するための多くの便利な方法を学ぶことができます

0