問題

Stack Overflow SQL Server 2005データベースには、気まぐれながらまれなデッドロック条件があります。

私はプロファイラを添付し、デッドロックのトラブルシューティングに関するを使用してトレースプロファイルを設定し、たくさんの例をキャプチャしました。奇妙なことは、デッドロック書き込みが常に同じであることです。

 UPDATE [dbo].[Posts]
SET [AnswerCount] = @p1, [LastActivityDate] = @p2, [LastActivityUserId] = @p3
WHERE [Id] = @p0
 

他のデッドロックステートメントはさまざまですが、通常は投稿テーブルの簡単で簡単な読み込みです。これは常にデッドロックで殺されます。ここに例があります

 SELECT
[t0].[Id], [t0].[PostTypeId], [t0].[Score], [t0].[Views], [t0].[AnswerCount], 
[t0].[AcceptedAnswerId], [t0].[IsLocked], [t0].[IsLockedEdit], [t0].[ParentId], 
[t0].[CurrentRevisionId], [t0].[FirstRevisionId], [t0].[LockedReason],
[t0].[LastActivityDate], [t0].[LastActivityUserId]
FROM [dbo].[Posts] AS [t0]
WHERE [t0].[ParentId] = @p0
 

完全に明確にするために、私たちは書き込み/書き込みデッドロックを見ていませんが、読み書きします。

現時点では、LINQとパラメータ化されたSQLクエリが混在しています。すべてのSQLクエリにwith (nolock)を追加しました。これはいくつかの助けになったかもしれません。私たちはまた、昨日修正した単一の(非常に)poorly-writedバッジクエリを持っていました。これは毎回20秒以上かかり、その上で毎分実行されていました。私はこれがいくつかのロック問題の原因だと期待していました!

残念ながら、私は約2時間前に別のデッドロックエラーが発生しました。同じ正確な症状、同じ正確な犯人の書き込み。

本当に奇妙なことは、上記のロック書き込みSQL文が非常に特定のコードパスの一部であるということです。これは、新しい回答が質問に追加されたときにのみ実行されます。新しい回答数と最後の日付/ユーザーで親質問を更新します。これは明らかに、私たちがやっている大量の読み取りの相対的なものではありません!私が知る限り、私たちはアプリのどこにでも膨大な数の書き込みをしていません。

私はNOLOCKが巨大なハンマーのようなものであることを認識していますが、ここで実行するクエリのほとんどは正確である必要はありません。あなたのユーザープロファイルが数秒であるかどうか気にしますか?

LinqでNOLOCKを使用することは、 Scott Hanselmanがここでを論じているので、もう少し難しいです。

私たちは、

 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
 

基本データベースコンテキストで、すべてのLINQクエリがこのセットを持つようにします。それがなければ、3-4行のトランザクションコードブロックで作成したすべてのLINQ呼び出しをラップする必要があります。これは醜いです。

私は、SQL 2005の些細な読み込みが書き込み時にデッドロックできることを少し不満に思っていると思います。私は書き込み/書き込みデッドロックが大きな問題であることを見ることができましたが、読んでいますか?私たちはここで銀行サイトを運営していない、私たちは毎回完璧な精度を必要としません。

アイデア?思考?


すべての操作に対して新しいLINQ to SQL DataContextオブジェクトをインスタンス化していますか、おそらくすべての呼び出しに対して同じ静的コンテキストを共有していますか?

ジェレミー、私たちは基本コントローラで1つの静的データコンテキストを共有しています。

 private DBContext _db;
/// <summary>
/// Gets the DataContext to be used by a Request's controllers.
/// </summary>
public DBContext DB
{
    get
    {
        if (_db == null)
        {
            _db = new DBContext() { SessionName = GetType().Name };
            //_db.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
        }
        return _db;
    }
}
 

すべてのコントローラ、またはページごとに新しいコンテキストを作成することをお勧めしますか?

  ベストアンサー

MSDNによると:

http://msdn.microsoft.com/en-us/library/ms191242.aspx

どちらかが COMMITTED SNAPSHOTを読むか、 SNAPSHOT ISOLATIONデータベースを許可する オプションは ON、論理コピー (バージョン)はすべてのデータに対して維持されます データベース。行が変更されるたびに 特定の取引によって、 データベースエンジンストアのインスタンス 以前にコミットしたバージョン tempdbの行の画像。それぞれ バージョンにはトランザクション トランザクションのシーケンス番号 変化をもたらしました 変更された行はリンクを使用して連鎖されます リスト。最新の行の値は常に 現在のデータベースに格納され、 格納されているバージョン管理された行に連鎖されています tempdbで。

ショートランザクションの場合、 変更された行のバージョンは、 バッファプールにキャッシュされていない のディスクファイルに書き込まれる tempdb データベース。 バージョン管理された行は短命です。 単に バッファプール オーバーヘッドが発生します。

余分なオーバーヘッドにはわずかなパフォーマンスペナルティがあるようですが、無視できるかもしれません。確かめるためにテストする必要があります。

本当に必要でない限り、このオプションを設定し、コードクエリからすべてのNOLOCKをREMOVEしてください。 NOLOCKsまたはデータベースコンテキストハンドラでグローバルメソッドを使用してデータベーストランザクション分離レベルを戦闘する場合は、Band-Aidsが問題になります。 NOLOCKSはデータ層の基本的な問題をマスクし、信頼性の低いデータを選択する可能性

 ALTER Database [StackOverflow.Beta] SET READ_COMMITTED_SNAPSHOT ON
 

  同じタグがついた質問を見る

sql-serversql-server-2005deadlock