mysql5.7なぜデッドロックをしようとすると、タイムアウトを待つことなくエラーが発生するのですか?

1707 ワード

問題の原因
個人がデッドロックを作る小さな実験をしました
Session1
Session2
Begin;
 
Select * from t where id=1 lock in share mode;
 
 
Begin;
 
Select * from t where id=1 lock in share mode;
 
Delete from t where id=1;//waiting
Delete from t where id=1;//すぐに間違いを報告します:Deadlock found when trying to get lock;try restarting transaction
 
 
私のmysqlに対する理解によると、デッドロックが現れた後、ゆっくりとタイムアウトを待ってからロールバックしなければならない.結局、ここで実行をノックしたかと思うと、すぐに間違いが報告された.明らかにタイムアウトではない.では、mysqlは各セッションが持っているリソースを保存すると思います.新しいsql文を実行するたびに、すべてのセッションを持っているリソースでスキャンして、デッドロックの可能性があるかどうかを確認します.しかしemmm、この戦略は効率が低いと感じます.
そこでmysqlがどんな検出メカニズムを使っているのか知りたいです.
答えの結論
5.7リリース開始、innodb_deadlock_detectスイッチ変数が導入され、デフォルトでオンになります.(show variables like'%innodb_deadlock_detect%';表示)
そこでmysqlは2つの方法でデッドロックを検出した:元の待機タイムアウトと新しいデッドロック検出.
デッドロック検出の原理は、トランザクションを頂点とし、ロックをエッジとする有向図を構築し、有向図にループが存在するかどうかを判断し、存在するとデッドロックがあるので、同時に大量のトランザクションが存在すると、検出が非常に遅くなる可能性があります.そこでmysqlはこれに対して上限制御を行った.運転中にエラーが発生した場合
TOO DEEP OR LONG SEARCH IN THE LOCK TABLE WAITS-FOR GRAPH, WE WILL ROLL BACK FOLLOWING TRANSACTION

これは、現在待機しているトランザクションの数が200の上限に達していることを示します.200以上のトランザクションの待機リストはデッドロックとみなされ、待機リストをチェックしようとしたトランザクションはロールバックされます.ロック・スレッドが待機リスト内のトランザクションが持つ1000000以上のロックを表示する必要がある場合、同じエラーが発生する可能性があります.(詳細はMySQL 5.7ドキュメントを参照)
ちなみに、デッドロック検出メカニズムのコードにデッドロックが発生する心配はありません.リソースを待つ必要がなく、デッドロックが発生する条件を備えていないためです.
答えを探している間に見つけた他の面白いポイント
innodbがトランザクションの完全なロールバックを実行すると、トランザクション設定のすべてのロックが解放されます.ただし、エラーによりsql文が1つだけロールバックされる場合、その文が設定したロックの一部が保持される可能性があります.これはinnodbがロー・ロックを後でどのロックがどの文によって設定されているか分からないフォーマットで格納しているためです.
  •  

  •