MySQL MVCCメカニズム原理の詳細な説明

MySQL MVCCメカニズム原理の詳細な説明

MVCCとは

MVCC は、Multi-Version Concurrency Control の略で、マルチバージョン同時実行制御のことです。 MVCC は同時実行制御方式であり、一般的にデータベース管理システムで使用され、プログラミング言語でデータベースやトランザクション メモリへの同時アクセスを実装します。

一般的に、MySQL データベースを使用する場合は、Innodb ストレージ エンジンを使用することが知られています。Innodb ストレージ エンジンはトランザクションをサポートしています。そのため、複数のスレッドが同時にトランザクションを実行すると、同時実行の問題が発生する可能性があります。このとき、同時実行性を制御できる方法が必要となり、MVCC がこの役割を果たします。

MySQL ロックとトランザクション分離レベル

MVCC メカニズムの原理を理解する前に、まず MySQL のロック メカニズムとトランザクション分離レベルを理解する必要があります。MyISAM ストレージ エンジンは別として、Innodb ストレージ エンジンには行ロックとテーブル ロックの 2 種類のロックがあります。テーブル ロックは 1 回の操作でテーブル全体をロックします。ロックの粒度は最も大きくなりますが、パフォーマンスは最も低く、デッドロックは発生しません。行ロックは一度に 1 行をロックします。ロックの粒度は小さく、同時実行性は高くなりますが、デッドロックが発生する可能性があります。

Innodb の行ロックは、共有ロック (読み取りロック) と排他ロック (書き込みロック) に分けられます。トランザクションが行に読み取りロックを追加すると、他のトランザクションは行の読み取りは許可されますが、書き込み操作は許可されません。他のトランザクションも行に書き込みロックを追加することはできませんが、読み取りロックは追加できます。

トランザクションが行に書き込みロックを追加すると、他のトランザクションはこの行に書き込むことはできませんが、読み取ることはできます。同時に、他のトランザクションはこの行に読み取り/書き込みロックを追加することはできません。

MySQL のトランザクション分離レベルを見てみましょう。これは次の 4 つのレベルに分かれています。

  1. コミットされていない読み取り: トランザクションは、他のトランザクションがまだコミットしていないデータを読み取ることができ、ダーティ リードが発生します。たとえば、給与テーブルがあるとします。最初にトランザクション A が開始され、次に ID 1 の従業員の給与が照会されます。この時点で給与が 1000 であるとします。このとき、トランザクション B も開始され、更新操作が実行され、ID 1 の従業員の給与が 100 減額されますが、トランザクションはコミットされません。このとき、トランザクション A のクエリ操作を再度実行すると、トランザクション B によって更新されたデータを読み取ることができます。この時点でトランザクション B がロールバックされると、トランザクション A は「ダーティ」なデータを読み取ります。トランザクション A が更新操作を実行すると、ファントム リードも発生する可能性があります。
  2. コミットされた読み取り: トランザクションは、コミットされた別のトランザクションによって変更されたデータのみを読み取ることができ、他のトランザクションがデータを一度変更してコミットした後、トランザクションは最新の値を照会できます。同じ例ですが、今回はトランザクション分離レベルが Read Committed であり、トランザクション B がトランザクションをコミットしないため、トランザクション A はトランザクション B によって更新されたデータを読み取ることができず、ダーティ データの生成を回避できます。しかし、トランザクション B がコミットされた後、トランザクション A は同じクエリを再度実行すると、データが変更されていることに気付きます。これは非反復読み取りと呼ばれ、同じトランザクションで同じクエリを複数回実行した結果が矛盾することを意味します。同時に、ファントム読み取りも依然として存在します。
  3. 繰り返し読み取り: トランザクションが初めてレコードを読み取った後、他のトランザクションがレコードの値を変更してコミットした場合でも、トランザクションがレコードを再度読み取るときは、毎回異なるデータを読み取るのではなく、最初に読み取った値を読み取ります。これが繰り返し読み取りです。この分離レベルは、非再現性の問題を解決しますが、ファントム読み取りが依然として発生する可能性があります。
  4. シリアル化: この分離レベルでは、同じレコードに対するすべての操作がシリアルであるため、ダーティ リードやファントム リードは発生しません。ただし、これは同時トランザクションではありません。

MySQL 元に戻すログ

MVCC は、最下層で Mysql の undo ログに依存しています。undo ログには、データベースの操作が記録されます。undo ログは論理ログであるため、レコードが削除されると、undo ログには対応する挿入レコードが記録されます。レコードが更新されると、undo ログには反対の更新レコードが記録されます。トランザクションが失敗してロールバックする必要がある場合は、undo ログの対応するコンテンツを読み取ることでロールバックできます。MVCC は undo ログを利用します。

MVCCの実装原則

MVCC の実装では、データベースの暗黙的なフィールド、UNDO ログ、および ReadView が使用されます。まず、暗黙のフィールドを見てみましょう。実際、MySQL はテーブルの各行の背後に次の隠しフィールドを暗黙的に記録します: DB_TRX_ID (最後に変更された (変更/挿入) トランザクションの ID)、DB_ROLL_PTR (このレコードの前のバージョンを指すロールバック ポインター)、および DB_ROW_ID (自動増分 ID。データ テーブルに主キーがない場合、クラスター化インデックスはデフォルトでこの ID を使用して作成されます)。

UNDO ログには 2 種類あります。挿入 UNDO ログは、新しいレコードが挿入されたときに生成される UNDO ログです。トランザクションがロールバックされたときにのみ必要で、トランザクションがコミットされた直後に破棄できます。更新 UNDO ログは、トランザクションが更新または削除されたときに生成される UNDO ログです。トランザクションがロールバックされたときだけでなく、スナップショットが読み取られたときにも必要です。したがって、気軽に削除することはできません。高速読み取りまたはトランザクション ロールバックがログに関係しない場合にのみ、対応するログがパージ スレッドによって均一にクリアされます。 MVCC は更新元に戻すログを使用します。

実際、UNDO ログにはバージョン チェーンが記録されます。データベースに次のようなレコードがあるとします。

ここで、このレコードを変更し、名前を tom に変更するトランザクション A があります。このときの操作フローは次のとおりです。

  • トランザクションAは最初に行レコードに行ロックを追加します。
  • 次に、行レコードを古いバージョンとしてUNDOログにコピーします。
  • コピー後、行名をtomに変更し、行のDB_TRX_IDの値をトランザクションAのIDに変更します。このとき、トランザクションAのIDは1であると仮定し、行のDB_POLL_PTRをUNDOログにコピーしたレコードに向けます。
  • トランザクションがコミットされると、ロックは解除されます

この時点での状況は以下のとおりです。

このとき、別のトランザクション B がこのレコードを変更し、年齢を 28 に変更します。このときの操作フローは次のとおりです。

  • トランザクションBは行レコードに行ロックを追加します。
  • 行レコードは、古いバージョンとして UNDO ログにコピーされます。UNDO ログにすでにレコードがある場合は、リンク リストのヘッダーとして、行レコードの UNDO ログの先頭に新しい UNDO ログが挿入されます。
  • コピー後、行のageを28に変更し、行のDB_TRX_IDの値をトランザクションBのIDに変更します。このとき、トランザクションBのIDは2であると仮定し、行のDB_POLL_PTRをUNDOログにコピーしたレコードに向けます。
  • トランザクションがコミットされた後にロックを解除する

この時点での状況は以下のとおりです。

上記から、異なるトランザクションまたは同じトランザクションによって同じレコード行に加えられた変更により、レコード行の UNDO ログによってバージョン チェーンが形成されることがわかります。UNDO ログ チェーンの先頭は最新の古いレコードであり、チェーンの末尾は最も古いレコードです。

ここで、ある状況を想定してみましょう。トランザクション A もトランザクション B もコミットされていないとします。この時点で、tom というレコードを変更し、age を 30 に変更するトランザクション C があります。その後、トランザクションがコミットされます。トランザクション C の ID は 3 です。同様に、レコードが UNDO ログに挿入されます。この時点で、UNDO ログ バージョン チェーンの最初のレコードの DB_TRX_ID は 3 です。

現在、tom という名前のレコードをクエリするトランザクション D があります。この時点で、スナップショット読み取りが有効になります。スナップショットは、トランザクションの開始時にクエリ操作によってトリガーされるデータ スナップショットです。ロック解除読み取りは、繰り返し読み取り分離レベルでのデフォルトのスナップショット読み取りです。スナップショット読み取りとは対照的に、現在の読み取りもあります。すべての更新操作は現在の読み取りです。スナップショット読み取り中に読み取りビューが生成されます。トランザクションがスナップショット読み取りを実行すると、データベースの現在のスナップショットが生成され、現在アクティブなトランザクションの ID が記録および維持されます。トランザクション ID は自動増分されるため、トランザクションが新しいほど ID が大きくなります。読み取りビューは可視性アルゴリズムに従っており、可視かどうかはある程度の判断が必要です。読み取りビューは、現在アクティブなトランザクション ID を記録するだけでなく、現在作成されている最大トランザクション ID も記録します。スナップショットを読み取るときは、読み取りビューと比較して可視性の結果を取得する必要があります。

読み取りビューでは、主に現在のトランザクションの ID とシステム内のアクティブなトランザクションの ID を比較します。比較ルールは次のとおりです。

まず、読み取りビューには、読み取りビューが生成された時点でシステム内でアクティブなトランザクションIDの配列が含まれており、一時的にid_listと呼ばれます。

次に、読み取りビューはid_list内の最小のトランザクションIDを記録します。これは一時的にlow_idと呼ばれます。

最後に、読み取りビューは、読み取りビューが生成された時点でシステムに割り当てられていないトランザクションIDも記録します。これは、現在の最大トランザクションID + 1で、一時的にhigh_idと呼ばれます。

  • 現在のトランザクションIDがlow_idより小さい場合、現在のトランザクションは表示されます。
  • 現在のトランザクション ID が high_id より大きい場合、現在のトランザクションは表示されません。
  • 現在のトランザクションはlow_idより大きくhigh_idより小さいです。次に、それがid_listにあるかどうかを判断します。ある場合、アクティブなトランザクションがまだコミットされていないことを意味します。現在のトランザクションは表示されませんが、アクティブなトランザクション自体には表示されます。id_listにない場合は、現在のトランザクションは表示されます。

可視性の結果が非表示の場合、比較のために、DB_ROLL_PTR を使用して、UNDO ログからレコードの DB_TRX_ID を取得する必要があります。特定の条件を満たす DB_TRX_ID が見つかるまでバージョン チェーンをトラバースすると、この DB_TRX_ID を持つ古いレコードが、現在のトランザクションが確認できる最新の古いバージョンになります。

上記はMySQL MVCCメカニズム原理の詳細な説明の詳細な内容です。MySQL MVCCメカニズム原理の詳細については、123WORDPRESS.COMの他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • MySQL トランザクション分離レベルと MVCC の詳細な説明
  • MySQL トランザクション分離はどのように実現されますか?
  • MySQL トランザクション分離レベルとロックメカニズムの問題に関する深い理解
  • MySql8.0 のトランザクション分離レベルエラーの問題を解決する
  • MySQL マルチバージョン同時実行制御 MVCC の基本原理の分析
  • MySQL マルチバージョン同時実行制御 MVCC の実装
  • Mysql MVCC マルチバージョン同時実行制御の詳細
  • MYSQL トランザクション分離レベルと MVCC

<<:  IIS web.config でクロスドメイン アクセスを設定する方法

>>:  HTMLドキュメントタイプの詳細な説明

推薦する

Windows で nginx を素早くインストールし、自動的に起動するように設定する

目次1. Windows システムでの Nginx のインストールと起動プロセス: 2. 起動時にN...

CSS スティッキーフッター実装コード

この記事では、CSS スティッキー フッターの実装コードを紹介し、共有します。詳細は次のとおりです。...

HTML 5 スタイルシートのリセット

この CSS リセットは、Eric Meyers の CSS リセットに基づいて変更されており、特に...

Linuxでmysqlの定期的なコールドバックアップを実装するためにmysqldump+expect+crontabを使用するアイデアの詳細な説明

目次1. 遭遇した問題2. アイデア3. コード1. 遭遇した問題私たちは皆、mysqldump を...

クラウド CentOS で Docker リモート サービス リンクを有効にするための実装手順

ここでは、dockerがインストールされたcentosサーバーを紹介し、リモートリンクサービスを開始...

JS配列の組み込みトラバーサルメソッドとその違いについての簡単な説明

目次forEach() (ES6) メソッドmap() (ES6) メソッドflatMap() メソ...

mysql8.0.20 のダウンロードとインストールおよび発生した問題 (図とテキスト)

1.ブラウザでmysqlを検索してダウンロードしてインストールしますアドレス: https://d...

MySQLデータベースの増分バックアップのアイデアと方法

MySQL データベースの増分バックアップを実行するには、データベース構成ファイル /etc/my....

マウスを置いたときに半透明効果のテキスト説明を実現するための純粋な CSS (初心者は必読)

効果は以下のとおりです。 例1 例2:例1[結婚式の計画]を例にとるHTML: <div cl...

CSS を使用して固定ナビゲーションと左右スライドを備えたスクロール バーを作成する方法

上に示すように、ナビゲーションは上部に固定されており、左右にスライドしてさらにオプションをクリックで...

Linux の GRUB ブート プログラムの暗号化の概要

目次1. GRUB暗号化とは何か2. grub暗号化手順3. grub暗号化のロック属性1. GRU...

MySQL 5.7 MGR シングルマスター決定マスターノード方式の詳細説明

当銀行のMGRは年末に開始されます。公式文書を読んだり、毎日テストを受けたりしなければなりません。毎...

ページ要素の絶対位置と相対位置に関するある程度の理解

今日から、定期的にちょっとした豆知識を整理していきます。簡単なものもあるかもしれませんが、どれも役に...

Linux サーバーのクイックアンインストールとノード環境のインストール (簡単に始められます)

1.まずnpmをアンインストールする sudo npm アンインストール npm -g 2. ノー...

InnoDB タイプの MySql によるテーブル構造とデータの復元

前提条件: データベースを復元するために必要な .frm ファイルと .ibd ファイルを保存します...