MySQLのMVCCマルチバージョン同時実行制御の実装

MySQLのMVCCマルチバージョン同時実行制御の実装

1 MVCCとは何か

MVCC の正式名称は、マルチバージョン同時実行制御です。データベースへの同時アクセスを提供するときにトランザクション内でメモリ読み取りを処理し、書き込み操作が読み取り操作をブロックするという同時実行の問題を回避します。

たとえば、プログラマー A がデータベース内の特定のコンテンツを読み取り、プログラマー B がこのコンテンツを変更しているとします (変更が約 10 秒続くトランザクション内で行われると仮定)。A は、この 10 秒以内に不整合なデータを見る可能性があります。B がコミットする前に、A は常に整合性のあるデータを読み取ることができるのでしょうか。

これに対処するにはいくつかの方法があります。最初の方法は、ロックベースの同時実行制御です。プログラマー B がデータを変更し始めると、データをロックします。この時点でプログラマー A がデータを読み取ると、読み取れず待機状態になっていることがわかります。B が操作を完了した後にのみ、データを読み取ることができます。これにより、A が矛盾したデータを読み取らないことが保証されますが、プログラムの実行効率に影響します。もう 1 つあります。MVCC です。各ユーザーがデータベースに接続すると、特定の瞬間のデータベースのスナップショットが表示されます。B のトランザクションがコミットされる前に、A は常に特定の瞬間のデータベースのスナップショットを読み取り、B のトランザクションでのデータ変更は読み取りません。B のトランザクションがコミットされた場合にのみ、A は B の変更を読み取ることができます。

MVCC をサポートするデータベースは、特定のデータを更新するときに、古いデータを新しいデータで上書きするのではなく、古いデータを古いものとしてマークし、別の場所に新しいデータ バージョンを追加します。したがって、同じデータの複数のバージョンが保存されますが、最新のものは 1 つだけです。

MVCC は、時間の一貫性を実現するソリューションを提供します。MVCC でトランザクションを読み取る場合、通常、タイムスタンプまたはトランザクション ID を使用して、アクセスするデータベースの状態とデータのバージョンを決定します。読み取りトランザクションと書き込みトランザクションは互いに分離されており、相互に影響を与えません。同じデータが読み取りトランザクションと書き込みトランザクションの両方からアクセスされると仮定します。実際には、書き込みトランザクションは新しいデータ バージョンを作成し、読み取りトランザクションは古いデータ バージョンにアクセスします。読み取りトランザクションは、書き込みトランザクションがコミットされるまで、新しいデータ バージョンにアクセスしません。

MVCC を実装する方法は 2 つあります。1 つ目は、データベースに複数のバージョンのデータ レコードを保存する方法です。これらの異なるバージョンのデータが不要になると、ガベージ コレクターがこれらのレコードを回収します。この方法は、PostgreSQL および Firebird/Interbase で採用されています。SQL Server も同様のメカニズムを使用しますが、違いは、古いバージョンのデータがデータベースに保存されるのではなく、メイン データベースとは異なる別のデータベース (tempdb) に保存される点です。 2 番目の実装方法では、データベースに最新バージョンのデータのみを保存しますが、元に戻す操作を行うと、古いバージョンのデータが動的に再構築されます。この方法は、Oracle および MySQL/InnoDB で使用されます。

2. InnoDBのMVCC実装メカニズム

MVCC は行レベル ロックのバリエーションと見なすことができ、多くの場合ロック操作を回避できるため、オーバーヘッドが低くなります。ほとんどの MVCC 実装では非ブロッキング読み取り操作が実装され、書き込み操作では必要な行のみがロックされます。 InnoDB の MVCC 実装は、特定の時点でのデータのスナップショットを保存することによって実現されます。トランザクションの実行にどれだけ時間がかかっても、その中に表示されるデータは一貫しています。つまり、トランザクションは実行中に互いに影響を及ぼしません。以下では、InnoDB での MVCC の実装について簡単に説明します。

InnoDB の MVCC は、各レコード行の後に 2 つの隠し列を保存することで実装されています。1 つの列には行の作成時刻が保存され、もう 1 つの列には行の有効期限 (削除時刻) が保存されます。もちろん、ここでの時刻はタイムスタンプではなく、システム バージョン番号です。新しいトランザクションが開始されるたびに、システム バージョン番号が増加します。 RR 分離レベルでは、MVCC は次のように動作します。

操作を選択します。

InnoDB は、現在のトランザクション バージョンよりも前のバージョン (またはそれと等しいバージョン) のデータ行のみを検索します。トランザクションによって読み取られる行は、トランザクションの開始前に存在しているか、トランザクション自体によって挿入または変更されたレコードであることが保証されます。

削除された行のバージョンは未定義であるか、現在のトランザクション バージョン番号よりも大きいです。トランザクションによって読み取られた行が、トランザクションの開始前に削除されていないことを確認できます。

挿入操作。新しく挿入された行の現在のバージョン番号を行バージョン番号として保存します。

削除操作。削除された行の現在のバージョン番号を削除マークとして保存します。

更新操作。これは、挿入操作と削除操作の組み合わせになります。挿入された行は現在のバージョン番号を行バージョン番号として保存し、削除では現在のバージョン番号が削除マーカーとして元の行に保存されます。

古いデータは実際には削除されていないため、クリーンアップする必要があります。InnoDB は、クリーンアップを実行するためにバックグラウンド スレッドを開始します。具体的なルールは、現在のシステム バージョンよりもバージョン番号が小さい行を削除することです。このプロセスはパージと呼ばれます。

3. 簡単な例

テーブルyang(を作成 
    id int 主キー auto_increment, 
    名前varchar(20));
}

システムのバージョン番号は 1 から始まると仮定します。

入れる

InnoDB は、新しく挿入された各行のバージョン番号として現在のシステム バージョン番号を保存します。
最初のトランザクション ID は 1 です。

トランザクションを開始します。
yang 値に挿入します (NULL、'yang')。
ヤン値(NULL,'long')に挿入します。
yang 値に挿入します (NULL、'fei')。
専念;

データ内の対応するテーブルは次のとおりです (最後の 2 つの列は非表示の列であり、クエリ ステートメントでは表示されません)

選択

InnoDB は各行を次の 2 つの条件と照合します。
a. InnoDB は、現在のトランザクション バージョンよりも前のバージョンのデータ行のみを検索します (つまり、行のシステム バージョン番号がトランザクションのシステム バージョン番号以下です)。これにより、トランザクションによって読み取られる行は、トランザクションの開始前に存在しているか、トランザクション自体によって挿入または変更されていることが保証されます。
b. 削除された行のバージョンは未定義であるか、現在のトランザクション バージョン番号より大きいため、トランザクションによって読み取られた行はトランザクションの開始前に削除されていないことが保証されます。
a と b の両方を満たすレコードのみがクエリ結果として返されます。

消去

InnoDB は、削除された各行の削除識別子として現在のシステム バージョン番号 (トランザクション ID) を保存します。
次の具体的な分析例を参照してください。
2 番目のトランザクション、ID は 2 です。

トランザクションを開始します。
ヤンから*を選択; //(1)
ヤンから*を選択します。 //(2)
専念;

仮定1

トランザクションID 2の実行中に(1)に達したときに、別のトランザクションID 3がテーブルにレコードを挿入すると仮定します。
3 番目のトランザクション ID は 3 です。

トランザクションを開始します。
yang 値に挿入します (NULL、'tian')。
専念;

表のデータは次のとおりです。

次に、トランザクション2の(2)を実行します。id=4のデータの作成時刻(トランザクションIDは3)、現在のトランザクションIDは2であり、InnoDBは現在のトランザクションID以下のトランザクションIDのデータ行のみを検索するため、トランザクション2の(2)ではid=4のデータ行は取得されません。トランザクション2の2つの選択文で取得されるデータは以下のもののみとなります。

仮定2

トランザクションID 2の実行中に、(1)を実行したと仮定します。トランザクションがトランザクション3を実行した後、トランザクション4を実行すると仮定します。
4番目のトランザクション:

トランザクションを開始します。  
id=1 の yang から削除します。
専念;

この時点でデータベース内のテーブルは次のようになります。

次に、トランザクションID 2のトランザクション(2)を実行します。SELECT検索条件に従って、作成時刻(作成トランザクションのID)が現在のトランザクションIDより小さく、削除時刻(削除トランザクションのID)が現在のトランザクションIDより大きい行を検索します。id=4の行は前述のとおりで、id=1の行は削除時刻(削除トランザクションのID)が現在のトランザクションIDより大きいです。そのため、トランザクション2(2)のselect * from yangもid=1のデータを検索します。そのため、トランザクション2の2つのselect文で検索されるデータは以下のようになります。

アップデート
InnoDB が UPDATE を実行すると、実際には新しいレコード行が挿入され、その作成時刻が現在のトランザクションの ID として保存されます。また、現在のトランザクション ID から UPDATE 対象の行への削除時刻も保存されます。

仮定3
トランザクション 2 (1) を実行した後、他のユーザーがトランザクション 3 と 4 を実行するとします。このとき、別のユーザーがこのテーブルに対して UPDATE 操作を実行します。
5番目のタスク:

トランザクションを開始します。
yang を更新し、name='Long' を設定します (id=2)。
専念;

更新の原則に従って、新しい行が生成され、変更される元の列の削除時間列にトランザクション ID が追加され、次のテーブルが作成されます。

トランザクション2の(2)の実行を続けます。SELECT文の検索条件に従って、次のテーブルが得られます。

トランザクション2(1)選択と同じ結果が得られます。

MySQL MVCC マルチバージョン同時実行制御の実装に関するこの記事はこれで終わりです。MySQL MVCC マルチバージョン同時実行制御に関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • MySQL マルチバージョン同時実行制御 MVCC の実装
  • MySQL マルチバージョン同時実行制御メカニズム (MVCC) ソースコードの詳細な説明
  • MySQL マルチバージョン同時実行制御 MVCC の詳細な研究
  • MySQL マルチバージョン同時実行制御 MVCC の基本原理の分析
  • MySQL マルチバージョン同時実行制御 MVCC の実装
  • Mysql MVCC マルチバージョン同時実行制御の詳細

<<:  ユーザーエクスペリエンスの概要

>>:  JavaScript 関数のカリー化

推薦する

localStorageの有効期限を設定するいくつかの方法

目次問題の説明1. 基本的な解決策2. 中間的な解決策3. 高度なソリューション4. ハードコアソリ...

Linux カーネル デバイス ドライバーのメモリ管理に関する注意事項

/************************ * Linux メモリ管理 *********...

WeChatアプレット開発で遭遇したことのない落とし穴のまとめ

目次getApp()ページエントリファイルの先頭に変数を定義しますwx.createSelector...

Dockerコンテナを閉じずに終了する方法の詳細な説明

Docker コンテナに入った後、コンテナを終了すると、コンテナは Exited 状態に変わります。...

LinuxにMySQLをインストールし、外部ネットワークアクセスを構成する例

設定手順1. DNSが設定されているかどうかを確認するDNSが設定されていない場合は、前の記事を参照...

Vue3 でマークダウン エディター コンポーネントを使用する方法

目次インストールコンポーネントのインポート基本的な使い方保存したマークダウンまたは HTML テキス...

VMware仮想マシンの起動時に黒い画面が表示される問題を解決する

# VMware ハードディスクの起動優先順位を調整するステップ 1: 電源をオンにすると、BIOS...

VMware 構成 VMnet8 ネットワーク方法の手順

目次1. はじめに2. 設定手順1. はじめに1. NAT モード (VMnet8) は、仮想マシン...

Docker イメージのダウンロードが遅すぎる場合の解決策

Docker イメージのダウンロードが停止したり、遅すぎたりするネットでいろいろな方法を検索しました...

MySQL 8.0.12 解凍バージョンのインストールチュートリアル

この記事では、MySQL 8.0.12解凍版のインストールチュートリアルを参考までに紹介します。具体...

MySQL 5.7 をインストールした後にコマンドライン ウィンドウを開くとクラッシュする問題の解決方法

序文最近、MySQL 5.7 をインストールしましたが、問題が見つかりました。コマンド ライン ウィ...

フォント名に従ってフォントを呼び出すと、ブラウザに必要なフォントが表示されます。

質問 1: ブラウザに必要なフォントを表示するように指示するにはどうすればよいでしょうか? フォント...

Vue が配列の変更を監視できない問題の解決方法

目次1. Vueリスナー配列2. vueが配列の変更を監視できない状況1. Vueリスナー配列Vue...

JavaScript で支払いの 10 秒カウントダウンを実現

この記事では、支払いの10秒カウントダウンを実現するためのJavaScriptの具体的なコードを参考...

Reactのコンテキストとプロパティの説明

目次1. 文脈1. 使用シナリオ2. 使用手順3. 結論2. 小道具の詳細1. 子供の財産2. 小道...