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


12

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

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

ご質問

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

回答:


11

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

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

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

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

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


4

あなたが尋ねた

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

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

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

InnoDBアーキテクチャ

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

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ログがデータを表示するために読み取られるか無視されるかを継続的に認識していました。

分離を管理するための行のロックを完全に理解するには、InnoDBトランザクションモデルとロックをお読みください。


1
まず、私の投稿の回答と修正に感謝します...それで、COMMITの前に、システムの他のユーザーには変更が表示されませんか?ここで、ユーザーは文字通りトランザクションを意味しますよね?READ UNCOMMITTEDはコミットされていないデータを読み取ることができるので、この分離レベルはこのデータをどこで読み取りますか?データベース内の特定のデータアイテムについて、コミットされていないデータのソースが複数存在する可能性はありますか?その場合、どのコミットされていないデータが読み取られますか?
Shuzheng 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.