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 関数のカリー化

推薦する

Mysql binlog ログファイルが大きすぎる場合の解決策

目次1. 関連するbinlog設定2. binlogに関する詳細設定2.1 バイナリログモードの変更...

CSSアニメーションがJSによってブロックされるかどうかについての簡単な議論

CSS のアニメーション部分は JS によってブロックされますが、transform のアニメーショ...

MySQL データの集約とグループ化

多くの場合、データを実際に取得せずに要約する必要があり、 MySQLこの目的のために特別な関数を提供...

MySQL 8.0.13 のダウンロードとインストールのチュートリアル(画像とテキスト付き)

MySQL は最もよく使用されるデータベースです。詳しく知るには、コンピュータにインストールする必...

Centos7.9 で独立したメール サーバーを構築するための詳細な手順

目次序文1. イントラネットDNS AレコードとMXレコードを構成する2. メールサーバの初期化設定...

1 つ以上のフィールドに基づいて重複データを検索する MySQL SQL ステートメント

SQLはテーブル内の重複レコードをすべて見つけます1. テーブルには id と name の 2 つ...

データベースのインデックス作成に関する知識ポイントのまとめ。必要な情報はすべてここにあります。

データベースインデックスについては皆さんもよくご存知だと思います。 インデックスは、データベース テ...

同じドメイン名を持つ Nginx プロキシのフロントエンドとバックエンドの分離プロジェクトの完全な手順

フロントエンド プロジェクトとバックエンド プロジェクトは分離されており、フロントエンドとバックエン...

MySQLトリガーの簡単な使用例

この記事では、例を使用して MySQL トリガーの簡単な使用方法を説明します。ご参考までに、詳細は以...

dockerプライベート倉庫の構築と利用の詳細説明

1. リポジトリイメージをダウンロードする docker プルレジストリ 2. プライベートウェアハ...

MySQL トリガーの紹介、トリガーの作成、使用制限の分析

この記事では、例を使用して、MySQL トリガーの概要、トリガーの作成方法、およびトリガーの使用上の...

Reactにおけるコンポーネント通信の詳細な説明

目次親コンポーネントは子コンポーネントと通信します子コンポーネントは親コンポーネントと通信しますコン...

JavaScript は、シンプルな虫眼鏡の最も完全なコード分析を実装します (ES5)

この記事では、参考までに、シンプルな虫眼鏡を実装するためのJavaScriptの具体的なコードを紹介...

mysql5.6.8 ソースコードのインストールプロセス

カーネル: [root@opop ~]# cat /etc/centos-release CentO...

コードブロックのハイライトをコピーして表示できる js プラグイン highlight.js + clipboard.js 統合

主に2つの側面から: 1. ハイライト/改行2. コードのコピーボタンこれら両方には既製のプラグイン...