web-dev-qa-db-ja.com

INSERT時のテーブルロック-最適化する方法

データベースにいくつかの長時間実行中のプロシージャがあるため、メインのテキストストレージテーブルにインスタントテーブルロックが発生し、Webアプリの他のすべてのリクエストが待機します(テーブルがほぼすべてのリクエストで使用されているため)。

セットアップ

  1. ASP.NET、Entity Framework、SQL Server 2008R2を使用するWebアプリケーション
  2. データ属性を持つ多くのテーブル(クラス戦略ごとのテーブル)
  3. 動的に定義されたテキスト用の1つのテーブル( "dbo.Translations")(翻訳を有効にするため)。
  4. このテーブルへの外部キーはありません

オブジェクトのテキストを適切な言語で取得するために、オブジェクトIDがテキスト値とともに変換テーブルに保存されます。

テーブル定義

したがって、変換テーブルは次のようになります。

dbo.Translations(ID varchar(36)、type varchar(10)、lang varchar(5)、value varchar(max))

一方、Typeはオブジェクトごとに定義され、langは 'en-GB'に似ています(関連なし)。

インデックス

テーブルには2つのインデックスがあります。IDのPK_Translations(クラスター化、一意ではない)すべての列のUNQ_Translations(非クラスター化、一意)

問題

テーブルはSELECTSとINSERTSの2つの操作を処理する必要があります。

更新と削除は一般的なユースケースではありません。

テーブルには、ほぼ1.000.000行と、ID、type、langに対するインデックスが保持されます。

Webアプリケーションが(複数の)レコードを挿入しようとすると、操作に時間がかかり、インスタントテーブルロックが作成されます。これにより、このテーブルに対する他のすべてのリクエストが停止し(他のテーブルへのリクエストもある可能性があるため、データベースロックのように見えることがあります!)、それらを待機させます。

インサート

大きなデータのINSERTSは、次の方法で行われます。

INSERT INTO Translations
   (Id, Typ, lang, value)
SELECT
   td.nId,
   td.Typ,
   td.lang,
   td.value
   FROM #tempDictionary td

注:#tempDictionairyは一時テーブルです

手順

以下の手順はテストされ、状況は改善されませんでした。

  1. コミットされていない読み取りでSELECTトランザクションを開始->変更なし
  2. インデックスのスパース性を50%に拡張して、挿入されたレコードを簡単に保存できるようにする->変更なし

SQL Serverがテーブル/データベースロックを作成する理由を確認するにはどうすればよいですか?

3
p0wl
  1. このプロセスがタブロックにエスカレートしていることを100%確信していますか?これはAdam Machanicのsp_whoisactiveで確認できます。プロセスの実行中(そしておそらくブロック中)にスナップショットを取得(プロシージャを実行)します。ロックとクエリプランを収集します。これにより、この問題の修正に必要な情報が得られます。挿入で待機しているspidが待機しているものに注意してください...ラッチで待機している場合-ページ分割の状況により、ブロック/ロックの問題がロックされます

  2. ロックのエスカレーションは、単一のステートメントがテーブルまたはインデックスの5Kロックを取得したときに発生することを覚えておいてください。 ( http://technet.Microsoft.com/en-us/library/ms184286(v = sql.105).aspx )paglockヒントを使用していることを発見しました(したがって、より粗いロックをより少なく取得します) )タブロックのエスカレーションを回避するために使用できます。

  3. 手順1で収集したクエリプランを見てください。挿入する行の基数の見積もり(つまり、selectステートメント)は何ですか... 5Kよりはるかに大きいですか?もしそうならあなたはループをコーディングしたいかもしれません-あなたが一度に2500行だけを挿入するように...

2
JoeOBrien