MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

PHPz
リリース: 2023-06-03 11:51:02
転載
817 人が閲覧しました

    1. MVCC

    MVCC (Multiversion Concurrency Control)、マルチバージョン同時実行制御とは何ですか。名前が示すように、MVCC はデータ行の複数のバージョン管理を通じてデータベースの 同時実行制御を実装します。このテクノロジーにより、InnoDB のトランザクション分離レベルでの一貫した読み取り操作が保証されます。つまり、別のトランザクションによって更新されている一部の行をクエリすることで、更新前の値を確認できるため、クエリを実行するときに別のトランザクションがロックを解放するのを待つ必要がありません。 。 MVCC には正式な標準はありません。MVCC の実装は DBMS ごとに異なる場合があり、普遍的に使用されるわけではありません (関連する DBMS ドキュメントを参照してください)。ここでは、InnoDB での MVCC の実装メカニズムについて説明します (他の MySQL ストレージ エンジンはサポートしていません)

    2 スナップショットの読み取りと現在の読み取り

    MySQL InnoDB での MVCC の実装は、主にデータベースを改善することです。同時実行パフォーマンス。

    読み取り/書き込み競合

    を処理するより良い方法を使用して、読み取り/書き込み競合がある場合でも、ロックなしノンブロッキング同時読み取りを実行できるようにします。 を達成しました。この読み取りは、現在の読み取りではなく、 スナップショットの読み取りを参照します。現在の読み取りは実際にはロック操作であり、悲観的ロックの実装です。 MVCC の本質は、楽観的なロック思考を使用する方法です。 2.1 スナップショット読み取り

    スナップショット読み取りは一貫性読み取りとも呼ばれ、スナップショット データを読み取ります。

    ロックなしの単純な SELECT はスナップショット読み取りです

    はロックなしの非ブロッキング読み取りです。例:

    select * from player where ...
    ログイン後にコピー
    スナップショット読み取りが発生する理由は、に基づいています。同時実行パフォーマンスの向上に関する考慮事項 スナップショット読み取りの実装は MVCC に基づいており、多くの場合、ロック操作が回避され、オーバーヘッドが削減されます。

    複数のバージョンに基づいているため、スナップショットの読み取りは必ずしも最新バージョンのデータを読み取るとは限りませんが、以前の履歴バージョンである可能性があります。

    スナップショット読み取りの前提は、分離レベルがシリアル レベルではないことです。シリアル レベルでのスナップショット読み取りは、現在の読み取りに縮退します。

    2.2 現在の読み取り値

    現在の読み取り値は、レコードの最新バージョン (データの履歴バージョンではなく、最新のデータ) を読み取ります。読み取り時には、他の同時トランザクションも確実に行う必要があります。現在のレコードを変更できません。読み取られたレコードはロックされます。ロックされた SELECT、またはデータの追加、削除、または変更を行うと、現在の読み取りが行われます。

    例:

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析3. レビュー

    3.1 分離レベルについてもう一度話しましょう

    トランザクションには 4 つの分離レベルがあるため、3 つの同時実行性の問題が発生する可能性があることがわかっています。

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析MysQL では、デフォルトの分離レベルは反復読み取りであり、ダーティな問題を解決できます。読み取りの問題を定義の観点からのみ見た場合、ファントム 読み取りの問題は解決されません。ファントム読み取りの問題を解決したい場合は、シリアル化を使用する必要があります。つまり、分離レベルを最高レベルに上げる必要がありますが、これによりデータベースのトランザクション同時実行機能が大幅に低下します。

    MVCC はロック メカニズムを使用できませんが、オプティミスティック ロックを通じて非反復読み取りとファントム読み取りの問題を解決します! ほとんどの場合、行レベルのロックを置き換えることができ、システムのオーバーヘッドを削減できます。

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析3.2 隠しフィールド、Undo ログ バージョン チェーン

    Undo ログ バージョン チェーンを確認しましょう。InnoDB ストレージ エンジンを使用するテーブルの場合、その集計クラスター インデックス レコード必要な 2 つの非表示列が含まれています。

    trx_id: トランザクションがクラスター化インデックス レコードを変更するたびに、トランザクションのトランザクション ID が trx_id 非表示列に割り当てられます。 roll_pointer: クラスター化インデックスのレコードが変更されるたびに、古いバージョンが元に戻すログに書き込まれます。この場合、この非表示列はポインターに相当し、レコードが見つかる前の情報が変更されます。

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    4. ReadView の MVCC 実装原則MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    MVCC の実装は次のものに依存します:

    隠しフィールド、Undo ログ、Read View

    4.1 ReadView とは

    MVCC メカニズムでは、複数のトランザクションのペアが更新されます。同じ行レコードから複数の履歴スナップショットが生成され、これらの履歴スナップショットは Undo ログに保存されます。トランザクションがこの行レコードをクエリする必要がある場合、行レコードのどのバージョンを読み取る必要がありますか? 現時点では、行の可視性の問題の解決に役立つ ReadView を使用する必要があります。

    トランザクションが MVCC メカニズムを使用してスナップショット読み取り操作を実行すると、読み取りビューが生成されます。このビューは ReadView です。トランザクションが開始されると、データベース システムの現在のスナップショットが生成されます。InnoDB は、各トランザクションの配列を構築して、システム内の現在アクティブなトランザクションの ID を記録および維持します (「アクティブ」とは、開始されているがまだ送信されていないことを指します)。 ).

    4.2 設計アイデア

    READ UNCOMMITTED分離レベルのトランザクションを使用します。コミットされていないトランザクションによって変更されたレコードを読み取ることができるため、トランザクションの最新のレコードを直接読み取ることができます。レコードです。バージョンは問題ありません。

    使用 SERIALIZABLE 分離レベル トランザクション。InnoDB では、レコードにアクセスするためにロックを使用することが規定されています。

    使用 READ COMMITTED分離レベル REPEATABLE READ のトランザクションは、 によって変更されたレコードがトランザクション によって送信されたことを確認する必要があります。別のトランザクションがレコードを変更したが、まだ送信していない場合は、そのレコードを読み取ることはできません。レコードの最新バージョンを直接読み取る場合、最も重要な問題は、バージョン チェーン内のどのバージョンが現在のトランザクションに表示されるかを判断することです。これは、ReadView によって解決される主な問題です。

    This ReadView主に 4 つが含まれます。 より重要な内容は次のとおりです。

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    4.3 ReadView のルール

    この ReadView では、特定のレコードにアクセスするときに、レコードの特定のバージョンが表示されているかどうかを確認するには、以下の手順に従ってください。

    • アクセスされたバージョンの trx_id 属性値が creator_trx_id 値と同じ場合ReadView では、現在のトランザクションが独自の変更されたレコードにアクセスしているため、このバージョンは現在のトランザクションからアクセスできることを意味します。 ReadView ## の

      up_limit_id# 値よりも小さく、現在のトランザクションが ReadView を生成する前にこのバージョンを生成したトランザクションがコミットされているため、現在のトランザクションからこのバージョンにアクセスできることを示します。
    • ##アクセスされたバージョンの trx_id 属性値が ReadView の
    • low_limit_id

      値以上の場合は、このバージョンを生成したトランザクションが現在のトランザクションが ReadView を生成した後に開かれたことを示します。現在のトランザクションではこのバージョンにアクセスできません。

    • アクセスされたバージョンの trx_id 属性値が ReadView の
    • up_limit_id

      low_limit_id の間にある場合、 trx_id 属性値が

      trx_ids
    • リストにあるかどうかを確認する必要があります。そうであれば、ReadView の作成時にこのバージョンを生成したトランザクションがまだアクティブであり、このバージョンにはアクセスできないことを意味します存在しない場合は、ReadView の作成時にこのバージョンを生成したトランザクションがコミットされており、このバージョンにアクセスできることを意味します。 4.4 MVCC の全体的な操作プロセス
    • これらの概念を理解した後、レコードをクエリするときにシステムが MVCC を通じてレコードをどのように見つけるかを見てみましょう:

    • 1. まず、トランザクション自体のバージョン番号 (トランザクション ID) を取得します;

    2。 GetReadView;

    • 3.取得したデータをクエリし、ReadView のトランザクション バージョン番号と比較します。

    • 4。Readview ルールを満たさない場合は、Undo ログから履歴スナップショットを取得する必要があります。 ;

    • 5.最終的に、ルールに準拠したデータが返されます。

    • データの特定のバージョンが現在のトランザクションに表示されない場合は、バージョン チェーンに従ってデータの次のバージョンを見つけ、引き続き上記の手順に従って可視性を確認します。など、バージョン チェーンの最後のバージョンまで続きます。最新バージョンが表示されない場合、レコードはトランザクションに表示されず、クエリ結果にも含まれません。

    • InnoDB では、MVCC は Undo Log Read View を通じてデータを読み取ります。Undo Log は履歴スナップショットを保存し、Read View ルールはデータの現在のバージョンが表示されているかどうかを判断するのに役立ちます。
    • 分離レベルが読み取りコミットの場合、トランザクション内の各選択クエリは読み取りビューを再取得します。

    分離レベルが再読み取り可能である場合、反復不可能な読み取りは回避されます。これは、トランザクションが初めて選択されたときに読み取りビューを 1 回しか取得しないためです。後続の選択ではこの読み取りビューが再利用され、

    は次のとおりです:

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    5. 例

    次のように仮定します。 トランザクション ID

    8MySQL マルチバージョン同時実行制御 MVCC インスタンス分析 である

    トランザクションによって Student テーブルに挿入されたレコードは 1 つだけです:

    MVCC は、READ COMMITTED と REPEATABLE READ の 2 つの分離レベルでのみ動作します。次に、READ COMMITTEDREPEATABLE READ

    の、いわゆるReadviewの生成タイミングの違いを見てみましょう。

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析5.1 READ COMMITTED

    分離レベルの下:

    READ COMMITTED: 各データ読み取りの前に ReadView が生成されます

    現在、トランザクション ID 10 と 20 の 2 つのトランザクションが実行されています:

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    説明: トランザクション実行中プロセスでは、レコードが初めて実際に変更されたとき (INSERT、DELETE、UPDATE ステートメントの使用など) にのみ、別のトランザクション ID が割り当てられ、このトランザクション ID がインクリメントされます。そのため、トランザクション ID を割り当てられるようにするために、トランザクション 2 で他のテーブルのいくつかのレコードを更新しました。

    現時点で、student テーブルの ID 1 のレコードによって取得されるバージョン リンク リストは次のとおりです。

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    ここで、READ COMMITED 分離レベルを使用するトランザクションが実行を開始すると仮定します。

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    この SELECT1 の実行プロセスは次のとおりです。

    ステップ 1: SELECT ステートメントを実行すると、最初に ReadView が生成されます。ReadView の trx_ids リストの内容は [ 10, 20]、up_limit_id10low_limit_id21creator_trx_id0
    ステップ 2: バージョン チェーンから表示可能なレコードを選択します。図からわかるように、最新バージョンの列 name の内容は '王五' です。 ##trx_id の値は 10 であり、これは trx_ids リスト内にあるため、可視性の要件を満たしておらず、roll_pointer に従って次のバージョンにジャンプします。 ステップ 3: 次のバージョンの列
    name の内容は '李思' であり、このバージョンの trx_id 値も # です##10trx_ids リストにも含まれているため、要件を満たしておらず、引き続き次のバージョンにジャンプします。 ステップ 4: 次のバージョンの列 name
    の内容は ‘Zhang San' で、このバージョンの trx_id 値は 8、ReadView の up_limit_id 値 10 より小さいため、このバージョンは要件を満たしています。ユーザーに返されるバージョンは、列名が「Zhang San」であるレコードです。 その後、トランザクション

    id

    10:

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析 に送信し、# # に進みます。 #トランザクション ID

    20 テーブル student のレコードを更新します (id1: #)

    ##現時点では、student テーブルの ID 1 のレコードのバージョン チェーンは次のようになります: MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    次に、READ COMMITTED 分離レベルを使用したトランザクション内で ID 1 のレコードの検索を続けます。

    は次のとおりです: MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    この SELECT2 の実行 処理は次のとおりです: MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    ステップ 1: SELECT ステートメントを実行すると、ReadView が別途生成されます ReadView の trx_ids リストの内容は [20]、up_limit_id は 20、low_limit_id は 21、creator_trx_id は 0 です。

    ステップ 2:バージョン チェーンから表示されているレコードを選択します。図からわかるように、最新バージョンの列名の内容は「Song Ba」であり、この tr_id 値はバージョンは 20 で、trx_ids リストに含まれているため、可視性の要件を満たしておらず、roll.pointer に従って次のバージョンにジャンプします。
    ステップ 3:次のバージョンの列名の内容は「Qian Qi」です。このバージョンの trx_id 値は 20 であり、これは trx_ids リストにも含まれているため、一致しません要件を満たしてから、次のバージョンにジャンプしてください。 ステップ 4: 次のバージョンの列名の内容は「王五」です。このバージョンの trx_id 値は 10 であり、ReadView の up_limit.id 値 20 より小さいため、このバージョンは要件を満たしています。 、そして最後にユーザーに与えられるバージョンは、列名が「王五」であるレコードです。
    同様に、トランザクション ID 20 のレコードも後で送信された場合、テーブル Student の ID 値 1 のレコードが READ CONMMITTED 分離レベルを使用してトランザクションで再度クエリされると、得られる結果は「Song Ba」になります。特定のプロセスについては分析しません。 5.2 REPEATABLE READ

    分離レベルの下:

    REPEATABLE READ 分離レベルを使用するトランザクションの場合、クエリ ステートメントは初回 ReadView が生成されると、後続のクエリは繰り返し生成されません。

    たとえば、システム内でトランザクション ID 10 と 20 の 2 つのトランザクションが実行されているとします。

    此刻,表student中id为1的记录得到的版本链表如下所示:

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    假设现在有一个使用REPEATABLE READ隔离级别的事务开始执行:

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    此时执行过程与read committed相同

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    然后再到刚才使用REPEATABLE READ隔离级别的事务中继续查找id为1的记录,如下:

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    这个SELECT2的执行过程如下:

    步骤1:因为当前事务的隔离级别为REPEATABLE READ,而之前在执行SELECT1时已经生成过ReadView了,所以此时直接复用之前的ReadView,之前的ReadView的trx_ids列表的内容就是[10,20],up_limit_id为10, low_limit_id为21 , creator_trx_id为0。
    步骤2:然后从版本链中挑选可见的记录,从图中可以看出,最新版本的列name的内容是’宋八’trx_id值为20,在trx_ids列表内,所以不符合可见性要求,根据roll_pointer跳到下一个版本。
    步骤3:下一个版本的列name的内容是’钱七’,该版本的trx_id值为20,也在trx_ids列表内合要求,继续跳到下一个版本。
    步骤4:下一个版本的列name的内容是’王五’,该版本的trx_id值为10,而trx_ids列表中是包含值为10的事务id的,所以该版本也不符合要求,同理下一个列name的内容是’李四’的版本也不符合要求。继续跳到下个版本。
    步聚5∶下一个版本的列name的内容是’张三’,该版本的trx_id值为80,小于Readview中的up_limit_id值10,所以这个版本是符合要求的,最后返回给用户的版本就是这条列c为‘张三’的记录。
    两次SELECT查询得到的结果是重复的,记录的列c值都是’张三’,这就是可重复读的含义。如果我们之后再把事务id为20的记录提交了,然后再到刚才使用REPEATABLE READ隔离级刷的事务中继续查找这个id为1的记录,得到的结果还是’张三’,具体执行过程大家可以自己分析一下。

    5.3 如何解决幻读

    假设现在表student中只有一条数据,数据内容中,主键id=1,隐藏的trx_id=10,它的undo log如下图所示。

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    假设现在有事务A和事务B并发执行,事务A的事务id为20,事务B的事务id为30。
    步骤1:事务A开始第一次查询数据,查询的SQL语句如下。

    select * from student where id > 1;
    ログイン後にコピー

    在开始查询之前,MySQL会为事务A产生一个ReadView,此时ReadView的内容如下: trx_ids=[20, 30 ] ,up_limit_id=20 , low_limit_id=31 , creator_trx_id=20。

    因为表student只有一条符合条件 where id>=1 的数据,所以会被查询出来。然后根据ReadView机制,发现该行数据的trx_id=10,小于事务A的ReadView里up_limit_id,这表示这条数据是事务A开启之前,其他事务就已经提交了的数据,因此事务A可以读取到。

    结论:事务A的第一次查询,能读取到一条数据,id=1。

    步骤2∶接着事务B(trx_id=30),往表student中新插入两条数据,并提交事务。

    insert into student(id,name) values(2,'李四');
    insert into student(id,name) values(3,'王五');
    ログイン後にコピー

    此时表student中就有三条数据了,对应的undo如下图所示:

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    ステップ 3: 次に、トランザクション A が 2 番目のクエリを開始します。反復読み取り分離レベルのルールに従って、トランザクション A はこの時点では ReadView を再生成しません。このとき、studentテーブルの3つのデータは、いずれもwhere id>=1の条件を満たすため、最初に検索されます。次に、ReadView の仕組みに従って、トランザクション A で各データが閲覧できるかどうかを判断します。
    1) まず、前述の通り、id=1 のデータはトランザクション A から見ることができます。
    2) 次に、id=2、trx_id=30 のデータがあります。このとき、トランザクション A は、この値が up_limit_id と low_limit_id の間にあることを検出するため、trx_ids 配列に 30 があるかどうかを判断する必要があります。 。配列ではトランザクション A の trx_ids=[20,30] となっているため、id=2 のデータはトランザクション A と同時に開始された他のトランザクションによって送信されたことを意味するため、このデータはトランザクション A からは見ることができません。
    3) 同様に、id=3 のこのデータの trx_id も 30 であるため、トランザクション A からは見ることができません。

    MySQL マルチバージョン同時実行制御 MVCC インスタンス分析

    #結論:トランザクション A の 2 番目のクエリは、id=1 のデータのみをクエリできます。これはトランザクション A の最初のクエリの結果と同じであるため、ファントム リード現象は発生せず、MySQL の反復可能な分離レベルではファントム リードの問題は発生しません。

    以上がMySQL マルチバージョン同時実行制御 MVCC インスタンス分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    関連ラベル:
    ソース:yisu.com
    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    最新の問題
    人気のチュートリアル
    詳細>
    最新のダウンロード
    詳細>
    ウェブエフェクト
    公式サイト
    サイト素材
    フロントエンドテンプレート
    私たちについて 免責事項 Sitemap
    PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!