web-dev-qa-db-ja.com

InnoDBはコミットする前にトランザクションデータをどこに格納しますか?

自宅でREAD_COMMITTEDREAD_UNCOMMITTEDを使用して、JDBCテクノロジーを使用したいくつかのテストを実行しました。

READ_UNCOMMITTEDは、実際にはコミットされていないデータを読み取ることができます。まだコミットされていないトランザクションからのデータ(UPDATEクエリを実行できます)。

ご質問

  • READ_UNCOMMITTEDトランザクションが別のトランザクションからコミットされていないデータを読み取ることができるように、コミットされていないデータはどこに保存されますか?
  • READ_COMMITTEDトランザクションがコミットされていないデータを読み取ることができない、つまり「ダーティリード」を実行できないのはなぜですか?この制限を強制するメカニズムは何ですか?
12
Shuzheng

"READ_UNCOMMITTEDトランザクションがコミットされていないデータを別のトランザクションから読み取ることができるように、コミットされていないデータはどこに保存されますか?"

コミットされていない新しいレコード(クラスター化されたPK)のバージョンは、ページ上のレコードの「現在の」バージョンとして扱われます。そのため、それらはバッファプールやテーブルスペース(たとえば、tablename.ibd)に格納できます。 READ-UNCOMMITTED以外でスナップショット/ビューを構築する必要があるトランザクションは、UNDOレコード( system tablespace に保存されている)を使用して、(履歴リストに従って)前のバージョンの行を構築する必要があります。 )。コミットされていないレコードを読み取るとき、InnoDBは バッファの変更 からいくつかのコミットされていないセカンダリインデックスレコードを読み取り、ユーザーにレコードを提示する前にそれらを適用する必要があります。

InnoDBでロールバックを比較的高価にできるのはこの動作です。また、更新されたレコードを保持している長時間実行されているアイドルトランザクションが潜在的なパフォーマンスの問題につながる可能性がある大きな要因です。これらのトランザクションは、パージ操作をブロックし、古いレコードバージョンの履歴リストが大きくなり、それらの古いバージョンを再構築するために必要なUNDOレコードが増えるためです。オンデマンドで、成長し続けます。 UNDOレコードの単一リンクリストである、より長い履歴リストを走査し、再構築するためにより多くの作業を行う必要があるため、レコードの古いバージョンまたはコミットされたバージョンを読み取る必要がある新しいトランザクションの速度が低下します。レコードの古いバージョン。したがって、クエリ処理を遅くする非ユーザー可視の作業で多くのCPUサイクル(内部ロックプリミティブ:ミューテックス、rw_locks、セマフォなど)を使用することになります。

うまくいけば、それは理にかなっていますか? :)

参考までに、 MySQL 5.7では、UNDOテーブルスペースとログをシステムテーブルスペースから移動できます で、自動的に切り捨てられます。パージオペレーションを妨げる長時間のトランザクションがある場合、それらは非常に大きくなり、履歴リストの長さが非常に長くなり、常に増大します。それらをシステムテーブルスペースに格納することは、巨大な/増大するibdata1ファイルの最も一般的な原因の1つであり、後でそのスペースを再利用するために切り捨て/縮小/バキュームすることはできません。

11
Matt Lord

あなたが尋ねた

rEAD_UNCOMMITTEDトランザクションがコミットされていないデータを別のトランザクションから読み取ることができるように、コミットされていないデータはどこに保存されますか?

あなたの質問に答えるためには、InnoDBアーキテクチャがどのように見えるかを知る必要があります。

次の画像は、数年前にPercona CTO Vadim Tkachenkoによって作成されました

InnoDB Architecture

MySQLドキュメントによると InnoDBトランザクションモデルとロック

COMMITは、現在のトランザクションで行われた変更が永続化され、他のセッションから見えるようになることを意味します。一方、ROLLBACKステートメントは、現在のトランザクションによって行われたすべての変更をキャンセルします。 COMMITとROLLBACKはどちらも、現在のトランザクション中に設定されたすべてのInnoDBロックを解放します。

COMMITとROLLBACKはデータの可視性を管理するため、READ COMMITTEDとREAD UNCOMMITTEDは変更を記録する構造とメカニズムに依存する必要があります

  1. ロールバックセグメント/スペースを元に戻す
  2. ログのやり直し
  3. 関係するテーブルに対するギャップロック

ロールバックセグメントと元に戻すスペースは、変更が適用される前に、変更されたデータがどのように見えるかを認識します。 REDOログは、データが更新されたように見えるようにロールフォワードする変更を認識します。

あなたも尋ねました

rEAD_COMMITTEDトランザクションがコミットされていないデータを読み取ることができない、つまり「ダーティリード」を実行できないのはなぜですか?この制限を強制するメカニズムは何ですか?

ログのやり直し、スペースの取り消し、ロックされた行が機能します。 InnoDBバッファープール( innodb_max_dirty_pages_pctinnodb_buffer_pool_pages_dirty および innodb_buffer_pool_bytes_dirty でダーティページを測定できる場所)も考慮する必要があります。

これに照らして、READ COMMITTEDは、どのようなデータが永続的に表示されるかを認識します。したがって、コミットされていないダーティページを探す必要はありません。 READ COMMITEDは、コミットされたダーティーリードにすぎません。 READ UNCOMMITTEDは、どの行がロックされるか、どのREDOログがデータを表示するために読み取られるか無視されるかを引き続き認識しているはずです。

分離を管理するための行のロックを完全に理解するには、 The InnoDB Transaction Model and Locking をお読みください。

4
RolandoMySQLDBA