デッドロックでのSQL Serverのレコードを再生することができません

通常遭遇したデッドロックは、ほとんどの場合、テストには、いくつかの試みの後に、特定の分析を一度にシーンを再現して、解決するために準じて行うことができ、正常に再現しませんでした、このデッドロックをシミュレートし
たプロファイルの追跡をロックしようとする際にご注文後、おそらくデッドロックの理由を推測するが、それでも再現することはできません、不要なトラブルを避けるために、ここではさらなる分析を行うために、しようとするシーンを復元するために可能な限り、テーブルをテストする方法です。
次のようにデッドロックのシナリオがある(表がどんなに合理的であるものを設計、インデックスが合理的ではない、書かれたSQL文は、デッドロックを解決するために、デッドロックが主な目的である分析することが合理的であることは別の問題です)

ターゲットテーブルTestDeadLock、およそ以下の構造
1、TestDeadLockテーブルヒープテーブル(自動インクリメントの主キーが、NONCLUSTERED主キーを持つ)、インデックスcol2.col3はidx_col2、idx_col3、Col2にない繰り返し、繰り返し値よりCOL3ありますテーブルのデータ量が、出現数十行または行、数千のあまりない
削除異なるCOL2のフィールドの複数の同時存在に応じて、2(TestDeadLockから削除ここでCOL2( X、Y、Z);)

作成 テーブルTestDeadLock 
    IDのint型の アイデンティティ11プライマリー キー クラスタ化されていない
    COL2 VARCHAR30 )、
    COL3 VARCHAR30 )、
    COL4 VARCHAR30 

図1に示すように、セッション1は(X、Y、Z)におけるCOL2テーブルAから削除行う;
2は、セッション2は、テーブルAから削除行う場合(LでCOL2 、M、N);
ここで、(X、Y、Zにおける削除対象列条件);および(L、M、N)で 、 このフィールドの値が繰り返されないデータがCol2に、全く交差が、COL3複数の条件に対応するフィールドの値が同じcol2があります

セッション1とセッション2デッドロック、xml_deadlock_report表示セッション1は、COL2のキーレベルUロックが保持されているU字ロックのキーレベルをCOL3待って、セッション1は、COL2のキーレベルを待って、COL3にUロックを保持するための鍵レベルでありますU字ロック
情報が待機ロックxml_deadlock_report、及び機密情報XXXXXXXXXX YYYYYYYYYYYYYも同様請求yyyyyyyyyyyy同様idx_col2インデックスIdを上記のようにXXXXXXXXXX idx_col3インデックスID、上記のように、置き換え以下

< リソースリスト> 
    < キーロックhobtid = "XXXXXXXXXXXXXX" DBID = "6" のObjectName = "" 索引名= "" ID = "lock12fe62f80" モード= "U" associatedObjectId = "XXXXXXXXXXXXXX" > 
    < 所有者リスト> 
        < 所有者ID = "プロセス- 2" モード= "U"  /> 
    </ 所有者リスト> 
    < ウェイターリスト> 
        < ウェイターID = "プロセス- 1"モード= "U" requestType = "待ちます"  />
    </ ウェイターリスト> 
    </ キーロック> 
    < キーロックhobtid = "YYYYYYYYYYYYY" DBID = "6" のObjectName = "" 索引名= "" ID = "lock126403100" モード= "U" associatedObjectId = "YYYYYYYYYYYYY" > 
    < 所有者リスト> 
        < 所有者ID = "プロセス- 1" モード= "U"  /> 
    </ 所有者リスト> 
    < ウェイターリスト> 
        <ウェイターID = "プロセスへ- 2" モード= "U"requestType = "待つ"  /> 
    </ ウェイターリスト> 
    </ キーロック> 
</ 資源リスト>

私は私自身の理解についてお話しましょう:
理論的には、セッションは、デッドロックが発生しない、Col2に上のターゲットデータが同じである順序をロックするための二つの文を2つの削除インデックスを取るだろう
、もちろん唯一の憶測を、 SQL文は、任意のロックヒント、少量のデータを追加していないので、任意の計画の実施が可能です。
唯一のデッドロックのステートメントから実行計画を取得する時間ではありません、デッドロックが発生した場合でも、それは双方が実行計画を使用した、確認することができませんでした。

 

テストおよびテストデータテーブルの構造、特徴:COL3のために、非常に多くの繰り返し値にもかかわらず、インデックスがまだある(ここでも、ここでは一時的にインデックスが合理的である脇に置く、この文は言って合理的です)

作成 テーブルTestDeadLock 
    IDのint型の アイデンティティ11プライマリー キー クラスタ化されていない
    COL2 VARCHAR30 )、
    COL3 VARCHAR30 )、
    COL4 VARCHAR30 

を作成 インデックス idx_col2をTestDeadLock(COL2)
 を作成 インデックス idx_col3 TestDeadLock(COL3)を


宣言 @i  int型 =  0を
ながら @i < 200000が
開始
    挿入  TestDeadLockの(CONCAT(' X0000000000 '@i)、鋳造ランド()* 10  として INT)、' テストが' に設定 @i  =  @i + 1 
端を

 

IDテスト対象インデックステーブル

例として(「X00000000003」、「X000000000020」)でCOL2、ここでその疑似列IDの取得にTestDeadLockから削除します

理論、文のSQLの実行では、(元のプロセスが最初に発見してから削除することで削除)を見つけるためにCOL2のインデックスを取り、その後、削除させていただきます、テストケースは、COL2にインデックスを取ることが期待されています

アプリケーション・プロセスを表示し、ロックを解除

それは見つけることができます

1がロックされたときにデータの部分を削除して一つずつ削除します

2,对于第一条记录(32a1976b7833),也即col2 = 'X000000000089'的记录,删除的加锁过程如下

  2.1 对(32a1976b7833),即col2 = 'X000000000089'的记录记录所在的page加共享排它锁,对(32a1976b7833)记录所在的行加U锁

  2.2  对(32a1976b7833)记录对应的主键所在的page加IX锁,主键行加RID级别的U锁

  2.3 对2.2 对(32a1976b7833)记录对应的RID所在的page加IX锁,主键行加RID级别的X锁

  2.4 对2.2 对(32a1976b7833)记录对应的主键所在的page加IX锁,主键行加RID级别的U锁

    2.5 对2.2 对(32a1976b7833)记录对应的主键所在的page加IX锁,主键行加KEY级别的X锁

  2.6 释放KEY与Page级别的X锁和IX锁

  2.7 重复2.1对(32a1976b7833)记录所在的page加共享排它锁,对(32a1976b7833)记录所在的行加U锁

  2.8 释放(32a1976b7833)以及其所在page的X锁和IX锁

  2.9 对(d12bea8cbd9f)这个记录,也即Col3字段上的索引依次加page上的IX锁,key上的X锁

  2.10(反向)依次释放Col3 key上的X锁,page上的IX锁

  2.11 依次释放上述其他的锁

简而言之,遵循两段锁协议(2PL),以行为基础,加锁与释放所过程独立,互不干扰。
因为走了Col2上的索引,这个过程大概是:先申请Col2上的U锁,找到其RID和主键索引,然后依次删除这RID和主键索引,然后再删除Col2上索引的key,最后删除对应的Col3上的索引key
最后释放所有上面申请的锁

上述是删除多条数据其中一条数据的加锁以及释放锁的过程,很清楚的看到,Col2上的U锁只是在第一步申请的,Col3上根本没有申请U锁,而是直接申请的X锁,然后删除,然后再释放
因为死锁双方的数据是互不交叉的,U锁又是单独只在Col2索引上申请的,那么为什么会出现死锁双方相互等待Col2与Col3上的U锁,从而造成死锁?
之前没有想明白,是因为就存在一种想当然的推断过程,两个session的删除语句都走col2上的索引,当然不会出现两个session相互申请Col2与Col3上的U锁
一旦存在Session1走Col2上的索引,Session2走Col3上的索引,才有可能出现ession相互申请Col2与Col3上的U锁的可能性

对于Session1和Session2

1,session1 执行delete from TableA where col2 in (x,y,z);
2,session2 执行delete from TableA where col2 in (l,m,n);

理论上说,或者相当然地说,都会走col2上的索引,但是不能完全肯定一定都会走Col2上的索引,或许有可能走全表扫描,或者有可能走Col3上的索引扫描
比如如下的强制索引提示,走任何一种执行计划,都是可能的,尽管可能会在主观上认为某些执行计划是不好的,但是这个语句在没有任何索引提示的时候,不能臆测一定会走col2上的索引
否则不会出现session双方持有了Col2索引上的U索引,申请Col3索引上的U锁,否则这个死锁就解释不通。

实际上,上述死锁,有可能是一个执行计划走了Col2上的索引查找方式删除,需要先在Col2索引上加U锁
一个是走了走了全表扫描造成的,类似于delete t from TestDeadLock t with(index(0)) where Col2 in ( 'X000000000089','X000000000095')的执行计划
后者先在Col3上加U锁,然后找到其对应的RID,主键索引,Col2上的索引,依次加U锁,加X索引,这样才潜在死锁的可能性

写不下去了,钻研SQL Server的人实在太少了,如果是MySQL,一定会有大神回去做深入的分析,这个case笔者多次尝试重现它,包括使用Python多线程的方式模拟当时的场景,都无疾而终,无法重现
发生死锁的这个真实情况下的场景,也不会经常出现,笔者也只是偶尔捞到死锁的xml_deadlock_report尝试作分析,均无果。

这个死锁,是笔者遇到的不多的无法重现或者模拟出来的死锁,但愿有高手感兴趣的话,进一步做分析尝试,即便是推翻笔者猜测的结论,得出更有说服力的结果。

以上。

 

おすすめ

転載: www.cnblogs.com/wy123/p/11575028.html