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入力ボックスの最適化により、ユーザーエクスペリエンスと使いやすさが向上します。

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

推薦する

MySQLのSQL文はインデックスを使用しません

インデックス集約を使用しない MySQL クエリご存知のとおり、インデックスを追加することはクエリ速...

一般的な Linux の問題に対する解決策の概要

1. VMwareでCentos7を接続し、固定IPを設定する1) まず、仮想イメージ名を右クリック...

HTML チュートリアル: HTML 水平線分

<br />このタグを使用すると、画面上に水平線を表示して、ページのさまざまな部分を区切...

nginx が動的と静的の分離を実装する方法の例

目次server1にnginxをデプロイするサーバーにlnmpを展開するノード3にhttpdをデプロ...

MySQL メモリテーブルと一時テーブルの使用方法の詳細な説明

MySQL メモリ テーブルと一時テーブルの使用メモリテーブル: セッション 1 $ mysql -...

Win10 での MySQL 8.0 ログインでユーザー 'root'@'localhost' のアクセスが拒否される (パスワード使用: YES) 問題の解決方法

最近、MySQL を学び始めました。インストールはスムーズに進み、インターネット上の既成のチュートリ...

Redis イメージの Docker インストールと設定手順

目次序文環境インストールMySQLコンテナを作成して起動する落とし穴を避けるための注意MySQLコン...

MySQL ロック制御同時実行方法

目次序文1. 楽観的ロックバージョンフィールドを追加する2. 悲観的ロック読み取りロック完全なテーブ...

モバイル端末の適応により、px は自動的に rem に変換されます。

まずpostcss-pxtoremをインストールします: npm install postcss-p...

基本的なウェブページパフォーマンス最適化ルールの簡単な概要

ブラウザのウェブページを最適化するためのいくつかのルールページの最適化静的リソース圧縮ビルド ツール...

Mysql8.0はソート問題を解決するためにウィンドウ関数を使用する

MySQL ウィンドウ関数の紹介MySQL は MySQL 8.0 以降、ウィンドウ関数をサポートし...

ショートカットアイコンとアイコンコードの違いの紹介

ステートメント 1: <link rel="shortcut icon" ...

スケーラブルな列の完全な例を実現するための Ant 設計 Vue テーブル

ant-design-vue テーブルのスケーラブルな列の問題に対する完璧なソリューション。固定列と...

JS に依存せずにレスポンシブ レイアウトを実現する CSS3 モバイル vw+rem メソッド

1. はじめに(1)vw/vhの紹介使用する前に、vw と rem とは何か、その機能について簡単に...