1

本番SQLServer2000データベースで、非常に厄介なデッドロック状態が発生しています。

主な設定は次のとおりです。

  • SQL Server2000EnterpriseEdition。
  • サーバーは、ATLOLEデータベースを使用してC++でコーディングされています。
  • すべてのデータベースオブジェクトは、ストアドプロシージャを介してアクセスされています。
  • すべてのUPDATE/INSERTストアドプロシージャは、内部操作をBEGIN TRANS ...COMMITTRANSブロックでラップします。

このようなインターネット上のいくつかの記事に従って、SQL Profilerを使用していくつかの初期トレースを収集しました(SQL Server 2005ツールを参照していることを無視してください。同じ原則が適用されます)。トレースから、2つのUPDATEクエリ間のデッドロックのように見えます。

問題が発生する可能性を減らすために、次のような対策を講じています。

  • SELECT WITH(NOLOCK)。ストアドプロシージャのすべてのSELECTクエリをWITH(NOLOCK)を使用するように変更しました。ダーティリードの影響は理解していますが、多くの自動更新を実行し、通常の状態ではUIに適切な値が設定されるため、クエリ対象のデータはそれほど重要ではありません。
  • コミットされていないを読んでください。サーバーコードのトランザクション分離レベルをREADUNCOMMITEDに変更しました。
  • トランザクションスコープの縮小。データベースのデッドロックが発生する可能性を最小限に抑えるために、トランザクションの保持時間を短縮しました。

また、ストアドプロシージャの大部分(BEGIN TRANS ... COMMIT TRANSブロック)内にトランザクションがあるという事実にも疑問を投げかけています。この状況では、トランザクション分離レベルはシリアライズ可能だと思いますよね?また、ストアドプロシージャを呼び出すソースコードでトランザクション分離レベルも指定されている場合はどうでしょうか。どちらが適用されますか?

これは処理集約型のアプリケーションであり、読み取り(より大きな割合)と一部の書き込みでデータベースに多くの影響を与えています。

これがSQLServer2005データベースの場合、スタックオーバーフローに関するデッドロックの問題について、Geoff Dalgasの回答を使用できます。これが、発生している問題にも当てはまります。ただし、現時点では、SQLServer2005へのアップグレードは実行可能なオプションではありません。

これらの最初の試みが失敗したので、私の質問は次のとおりです。ここからどのように進みますか?デッドロックの発生を減らす、または回避するためにどのような手順を実行しますか、または問題をより適切に明らかにするためにどのコマンド/ツールを使用する必要がありますか?

4

4 に答える 4

1

いくつかのコメント:

  1. ストアドプロシージャで明示的に指定された分離レベルは、呼び出し元の分離レベルを上書きします。

  2. sp_getapplockが2000で利用可能な場合、私はそれを使用します。

    http://sqlblogcasts.com/blogs/tonyrogerson/archive/2006/06/30/855.aspx

  3. 多くの場合、シリアル化可能な分離レベルにより、デッドロックが発生する可能性が高くなります。

  4. 2000年の優れたリソース:

    http://www.code-magazine.com/article.aspx?quickid=0309101&page=1

また、バートダンカンのアドバイスのいくつかが当てはまるかもしれません:

http://blogs.msdn.com/bartd/archive/2006/09/09/747119.aspx

于 2009-06-01T23:14:56.693 に答える
0

アレックスの答えに加えて:

  • コードを目で見て、テーブルが同じ順序でアクセスされているかどうかを確認します。最近これを行い、コードを常に親、次に子に並べ替えました。システムは成長し、コードと機能はより複雑になり、より多くのユーザーになりました。デッドロックが発生し始めただけです。

-トランザクションを短縮できるかどうかを確認します(たとえば、後で開始、早く終了、処理を減らす)

  • 失敗させたくないコードを特定し、他のコードでSET DEADLOCK PRIORITY LOWを使用します。これを使用して(SQL 2005にはここにさらに多くのオプションがあります)、一部のコードがデッドロックされて他のコードが犠牲にならないようにします。

  • トランザクションの開始時に何かを準備するためにSELECTがある場合は、HOLDLOCK(おそらくUPDLOCK)を検討して、この間ロックを維持します。これを時々使用するので、他のプロセスによるこのテーブルへの書き込みを停止します。

于 2009-06-02T04:36:01.333 に答える
0

私の推測では、次のいずれかのデッドロックが発生していると思います。

  1. DML(おそらく更新)ステートメントがテーブルロックへのエスカレーションを取得しているため、または
  2. 異なるストアドプロシージャが、トランザクション内の同じテーブルに異なる順序でアクセスしています。

これに対処するために、最初にストアドプロシージャを調べ、変更ステートメントに必要なインデックスが含まれていることを確認します。

注:これは、ターゲットテーブルとソーステーブルの両方に適用されます(NOLOCKにもかかわらず、UPDATEのソーステーブルもロックされます。ユーザーストアドプロシージャのスキャンのクエリプランを確認してください。バッチ操作や一括操作とは異なり、ほとんどのユーザークエリとDMLはテーブル行の小さなサブセットであるため、テーブル全体をロックしないでください。

次に、ストアドプロシージャをチェックして、ストアドプロシージャ内のすべてのデータアクセスが一貫した順序で実行されていることを確認します(通常、[親]-> [子]が優先されます)。

于 2009-06-02T05:37:20.493 に答える
0

私のセットアップシナリオでデッドロックが発生した理由は、すべてのインデックスの後でした。テーブルの主キーには(デフォルトで生成された)non clusteredインデックスを使用していました。インデックスに変更するとclustered、問題が修正されました。

于 2009-07-29T07:29:56.030 に答える