sql >> データベース >  >> RDS >> Sqlserver

テーブルでの選択/更新操作による SQL デッドロック

    デッドロックの原因となっている 2 つのクエリは、SELECT です。 以下 (process id="process3980de4558" ):

    select @existing = team_it_cube_attr_05 from tbl_Ref_Attr_Prod_Team where prod_id = @rec_key
      

    そして UPDATE 以下のクエリ (process id="process386ed48188" ):

    UPDATE D
    SET D.team_rss_attr_01 = LEFT(S.mkt_prodchar_13,25)...
      

    <resource-list> セクションは SELECT に注意します クエリがページの排他 (X) ロックを所有しており、データの読み取り中に別のページでインテント共有 (IS) ロックを取得しようとしていました。 UPDATE クエリは既に IS ロックを所有しており、更新を実行するためにページで X ロックを取得しようとしました。

    このテーブルに対する結合を考えると:

    ...from tbl_Ref_Attr_Prod_Team where prod_id = @rec_key...
    ...INNER JOIN tbl_Ref_Attr_Prod_Team D ON D.prod_key=P.prod_key...
      

    SELECT クエリはすでに排他ロックを所有しています。これはおそらく、すでに UPDATE を実行した大きなトランザクションの一部であることを意味します 以前のクエリで。以前のクエリからのロックは、トランザクション中にデータの整合性を維持するために維持されます (トランザクション分離レベル ).

    UPDATE クエリはテーブル tbl_Ref_Attr_Prod_team を読み取る必要があります .データの読み取り中に、ページと行でインテント共有ロックを取得します。 UPDATE クエリが一致する行を見つけると、IS ロックを X ロックに変換しようとします。 IS ロックは X ロックと互換性がありません。 SELECT クエリは、これらのページの 1 つ以上で既に IS ロックを持っており、クエリは互いにデッドロックしています。

    考えられる原因の 1 つは、tbl_Ref_Attr_Prod_team.prod_key にインデックスがないことです。 .この列にインデックスがないと、UPDATE クエリは、テーブル tbl_Ref_Attr_Prod_team 内のすべての行をスキャンします .

    prod_key にインデックスが存在する場合でも 、テーブルに少数の行がある場合、SQL Server は、クエリがインデックスをシークする代わりにテーブル全体をスキャンした方がパフォーマンスが向上すると判断する場合があります。デッドロックが発生したときにクエリ プランを記録すると、この理論が検証されます。

    新しいデータベースをステージングするときに、小さなテーブルのデッドロックが定期的に発生します。最初は、テーブルは小さく、テーブル スキャンはあらゆる種類のデッドロックを引き起こします。その後、テーブルが大きくなると、計算されたテーブル スキャンのコストがインデックスのシーク コストを上回り、デッドロックは発生しなくなります。行数が非常に少ないテスト環境では、FORESEEK を使用することに頼りました。 および WITH INDEX スキャンの代わりにインデックスシークを強制するヒント。 SQL Server 2016 のクエリ ストア機能を介してクエリ プランを強制できることを楽しみにしています。




    1. クエリビルダーの条件付きパラメーター

    2. クエリが多すぎますか?

    3. PHPがMYSQLデータベースに空白の行/フィールドを追加しないようにする方法

    4. MS SQL の範囲からランダムな値を取得しますか?