MySQL はどのようにしてマルチバージョンの同時実行性を実現するのでしょうか?

MySQL はどのようにしてマルチバージョンの同時実行性を実現するのでしょうか?

MySQL マルチバージョン同時実行

1. マルチバージョン同時実行制御

コミットされていない読み取りではダーティ リード、ファントム リード、非反復読み取りが発生し、コミットされた読み取りではファントム リードと非反復読み取りが発生し、反復読み取りではファントム リードが発生する可能性があり、シリアル化ではこれらの問題は発生しないことがわかっています。

では、InnoDB はこれらの問題をどのように解決するのでしょうか?あるいは、ダーティ リード、ファントム リード、非反復リードの根本的な原因について考えたことはありますか?

これが、今日お話しする主役である、マルチバージョン同時制御とも呼ばれるMVCC (Multi-Version Concurrent Controll) です。 InnoDB は、複数の同時トランザクションをサポートするストレージ エンジンです。データベース内の読み取り/書き込み操作を同時に実行できるため、ロックによる読み取りブロックを回避できます。

MVCC のおかげで、トランザクション B が id=1 のデータを更新しても、トランザクション A の id=1 の読み取り操作はブロックされません。非ブロッキングの理由は、ロックなしで一貫した読み取りを行うためです。では、一貫した読書とは何でしょうか?

1. 一貫した読み取り

簡単に言うと、クエリが実行されると、InnoDB は現時点でのデータベースのスナップショットを作成します。スナップショットが作成されると、現在のクエリはスナップショットの作成前に送信されたトランザクションの変更のみを認識できます。スナップショットの作成後に送信されたトランザクションは、現在のクエリでは認識されません。

もちろん、現在のトランザクション自体によって更新されたデータは例外です。現在のトランザクションによって変更された行は、再度読み取られたときに最新のデータを取得できます。その他の行の場合、読み取られるバージョンは、スナップショットを作成した時点のバージョンのままです。

このスナップショットは、InnoDB のトランザクション分離レベルの鍵となります。

(Read Committed分離レベルでは、トランザクション内の各一貫性のある読み取りによってスナップショットが再生成されます。繰り返し読み取り分離レベルでは、トランザクション内のすべての一貫性読み取りは、最初の一貫性読み取りによって生成されたスナップショットのみを使用します。

このため、上の図では、トランザクション B がトランザクションをコミットした後、変更は読み取りコミット分離レベルで確認できますが、反復可能読み取り分離レベルでは確認できません。これは基本的に、読み取りコミットスナップショットが再生成されるためです。

Read Committed および Repeatable Read 分離レベルでは、SELECT ステートメントはデフォルトで一貫性のある読み取りを使用し、一貫性のある読み取りシナリオではロックは追加されません。その他の変更操作も同期的に実行できるため、MySQL のパフォーマンスが大幅に向上します。これが MVCC マルチバージョン同時実行制御の実装原理です。このタイプの読み取りは、スナップショット読み取りとも呼ばれます。

トランザクション中に他のトランザクションの送信をすぐに確認したい場合はどうすればよいでしょうか?方法は2つあります:

(1)コミット読み取り分離レベルを使用する(2)共有ロックまたは排他ロックのいずれかでSELECT文をロックする。具体的には、 FOR SHAREFOR UPDATE
もちろん、2 番目の方法で対応するレコードに追加されたロックがSELECTによって追加されたロックと相互に排他的である場合、 SELECTブロックされます。このタイプの読み取りは、現在の読み取りとも呼ばれます。

上記の説明を理解したら、次に MVCC の実装方法を尋ねられたときに、一貫性のある読み取り (スナップショット読み取り) と現在の読み取りの観点から説明したり、さまざまな分離レベルでの一貫性のある読み取りスナップショットの更新メカニズムについて説明したりできます。

しかし、それだけでは十分ではないと思います。さらに深く理解し続ける必要があります。スナップショットしか分からないので、最下層ではどのように実装されるのでしょうか?実のところ、まだ分かりません。

2. 一貫した読書の原則についての深い理解

当然のことながら、異なる一貫性のある読み取りでは異なるバージョンのデータが読み取られる可能性があるため、これらは MySQL に保存される必要があります。そうしないと、読み取ることができません。はい、これらのデータは InnoDB テーブルスペース、具体的には Undo テーブルスペースに保存されます。

InnoDB で MVCC を実装するための鍵は実際には 3 つのフィールドであり、データ テーブルの各行には次の 3 つのフィールドがあります。

  • DB_TRX_IDフィールドは 6 バイトで、データ行を最後に挿入または更新したトランザクションの一意の識別子を格納するために使用されます。挿入と更新だけですか? と疑問に思うかもしれません。削除するとどうなりますか?実際、InnoDB 内では、削除は実際には更新操作であり、行内の特定のフラグ ビットを更新して削除済みとしてマークするだけです。
  • DB_ROLL_PTRフィールドには 7 バイトあります。これはロールバック ポインターと呼ばれ、ロールバック セグメントに格納されている特定の Undo ログを指します。現在のデータ行が更新された場合でも、ロールバック ポインターを使用して更新前の履歴バージョン データを取得できます。
  • DB_ROW_IDフィールドは 6 バイトです。これは、InnoDB によってデータ行に与えられる一意の識別子です。この一意の識別子は、テーブル構造を定義するときに定義される単調に増加する主キーと同様に、新しいデータが挿入されると単調に増加します。 DB_ROW_ID はクラスター化インデックスに含まれますが、他の非クラスター化インデックスには含まれません。

DB_ROLL_PTR を通じて最新の Undo ログを取得し、対応する各 Undo ログをその前の Undo ログにポイントします。このようにして、異なるバージョンを接続してリンク リストを形成できます。異なるトランザクションは、要件とルールに従ってリンク リストから異なるバージョンを選択し、読み取るため、次の図に示すように、マルチバージョンの同時実行制御が実現されます。

Undo Log について知らない人もいるかもしれませんが、次の点を覚えておいてください。

Undo ログは、トランザクションが開始される前のデータ ステータスを記録します。これは、Git のコミットに少し似ています。コミットを送信し、非常に複雑な要件に取り組み始めます。その後、イライラして、これ以上変更を加えたくなくなります。git reset --hard $last_commit_id を直接実行してロールバックできます。最後のコミットは、Undo ログと見なすことができます。興味がある場合は、Redo ログと Undo ログに基づく MySQL クラッシュ リカバリ プロセスを確認してください。

2. 元に戻すログの構成

トランザクションがコミットされた後に、Undo ログは削除されるべきではないのかと疑問に思う人もいるかもしれません。なぜ MVCC を通じて以前のデータを確認できるのでしょうか?

実際、InnoDB では、Undo ログは次の 2 つの部分に分かれています。

  • 元に戻すログを挿入
  • 元に戻すログを更新

Insert Undo Log の場合、トランザクションがコミットされると Insert Undo Log は完全に役に立たなくなるため、トランザクションでエラーが発生した場合のロールバックにのみ使用されます。そのため、トランザクションがコミットされた後は Insert Undo Log は削除されます。

Update Undo Log は異なります。MVCC 一貫性読み取りに使用でき、異なるバージョンのリクエストのデータ ソースを提供できます。つまり、Update Undo Log はまったく削除できないということですか?一貫性のある読み取り要求がいつ来るかわからないため、占有されるスペースがどんどん大きくなってしまいます。

はい、しかし完全ではありません。

一貫性のある読み取りは、本質的に複数のトランザクションを同時に処理することであり、異なるデータ バージョンを必要に応じて異なるトランザクションに提供する必要があります。したがって、現在トランザクションが存在しない場合は、Update Undo Log を強制終了できます。

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

以下もご興味があるかもしれません:
  • MySQLフィルタリングレプリケーションのアイデアの詳細な説明
  • MySQL 外部キー (FOREIGN KEY) の使用例の詳細な説明
  • MySQL のストアド プロシージャを使用して 100 万件のレコードをすばやく生成する方法
  • Pythonインターフェース自動化はpymysqlデータベース操作プロセスを簡単に分析します
  • MySQL トランザクション制御フローと ACID 特性
  • MySQLはストアドプロシージャを使用して数百万のデータを素早く追加します。サンプルコード
  • MySQL で重複時間を削除して時間差を計算する実装
  • MySQL データベースでは、datetime、bigint、timestamp を使用して時間の選択を表します。時間を保存するのに最も効率的なのはどれですか?
  • MySQL グローバルロックとテーブルレベルロックの具体的な使用法
  • Redo ログと Undo ログに基づく MySQL クラッシュ回復の分析

<<:  HTML入力ボックスの最適化により、ユーザーエクスペリエンスと使いやすさが向上します。

>>:  フロントエンドのパフォーマンス最適化 - フロントエンドエンジニアが話し合うべき問題点

推薦する

Vue ページ スタック マネージャーの詳細

目次2. 試した方法2.1 キープアライブ2.2 ネストされたルートを持つ CSS 3. 機能説明4...

Linux での sshd サービスとサービス管理コマンドの詳細な説明

sshd SSH は Secure Shell の略で、アプリケーション層のセキュリティ プロトコル...

MySQL でスロークエリを有効にする方法の例

序文スロー クエリ ログは、MySQL で非常に重要な機能です。MySQL のスロー クエリ ログ機...

MySQLトランザクション処理の使用方法とサンプルコードの詳細な説明

MySQL トランザクション サポートは、MySQL サーバー自体にバインドされているのではなく、ス...

CSS は Alibaba ベクター ライブラリを使用して、対応する位置に見栄えの良いアイコン効果をすばやく追加します (サンプル コード)

Alibaba ベクターアイコンライブラリにアクセスAlibaba ベクターアイコンライブラリ好き...

VMware 仮想マシンのインストール Apple Mac OS の超詳細なチュートリアル

目次要約する仕事の都合で Apple の Mac OS に対応するソフトウェアをインストールする必要...

JS における ES6 継承と ES5 継承の違い

目次継承ES5 プロトタイプ継承ES6 クラス継承両者の違いES5プロトタイプ継承の内部実装ES6 ...

開発をスピードアップできる VueUse ライブラリ 5 つ (まとめ)

目次VueUse にはどのようなユーティリティがありますか? VueUseをVueプロジェクトにイン...

TypeScript ジェネリックを簡単に説明する方法

目次概要ジェネリック医薬品とはビルドシステムジェネリック医薬品の一般的な理解ジェネリッククラスジェネ...

Linux でユーザー アカウントをロックおよびロック解除する 3 つの方法

組織内で何らかのパスワード ポリシーがすでに実装されている場合は、この記事を読む必要はありません。た...

Vueはダイアログのカプセル化を実装します

目次Vue2 ライティングVue3プラグインのバージョンの記述Vue3 動的コンポーネントの記述書き...

npm 淘宝ミラー変更説明

1. トップレベルの使用法1. cnpmをインストールする npm i -g cnpm --regi...

MySQL 5.7.31 64 ビット無料インストール版チュートリアル図

1. ダウンロードダウンロードアドレス: https://dev.mysql.com/get/Dow...

Dockerはポートを介してコンテナに接続します

Dockerコンテナ接続1. ネットワークポートマッピングPythonアプリケーション用のコンテナを...