INSERTで"enq:TX – row lock contention"
恥ずかしながら、INSERTで行ロック解放待ちが起こるということをつい先日になって知りました。言われてみれば当然な話で、本当に恥ずかしい…。
発端はしごとで触っているOracle DatabaseでINSERT文を実行するセッションがイベント"enq:TX – row lock contention"
で停止状態になっている事象を発見したことです。このセッションの情報をGV$SESSION
動的パフォーマンスビューで確認すると、当然のことながらカラムBLOCKING_SESSION
に原因となるセッションIDが設定されています。そしてこの原因セッションについてGV$SESSION
の情報を調べると、カラムPREV_SQL
にこれまた別のINSERT文が設定されており、カラムEVENTには"SQL*Net message from client"
…。
ようするに、こういうシナリオですね。先行する原因セッションが表AにINSERTしたあと同じトランザクションで別の表BへのINSERTを実施し、その後何らかの理由でユーザ側コードが停止状態に遷移。新しいSQLが実行されるわけでもなく、さりとてトランザクションが終了するわけでもない状態です。そこに別のセッション(被害者セッション)が登場し表AにINSERTしようとしたところで、行ロック解放待ち"enq:TX – row lock contention"
に突入…。
「なかった行を追加するのに行ロックなぞあるものか」と思っていましたが、RDBMSは単なるレコードの集合だけを管理するものではありません。一意性制約やそれを管理するためのB木索引、広域のロックを発生させるビットマップ索引などの仕組みが組み込まれています。してみれば制約や索引構造の一貫性を維持するため「行を登録する」というオペレーションを行うに際しても行ロックは必要になるわけです。
Google先生にあれこれ質問して、知ったあとではなんとも「当たり前」な話でした。