MySQL のほとんどのトランザクション ストレージ エンジンの実装は、単純な行レベルのロックではありません。同時実行パフォーマンスの向上を考慮して、通常はマルチバージョン同時実行制御 (MVCC) を同時に実装します。 MySQL だけでなく、Oracle や PostgreSQL などのデータベース システムも MVCC を実装していますが、MVCC には統一された標準がないため、実装メカニズムが異なります。
MVCC は行レベルのロックの一種と考えることができますが、多くの場合ロック操作が回避されるため、オーバーヘッドが低くなります。実装メカニズムは異なりますが、そのほとんどはノンブロッキング読み取り操作を実装し、書き込み操作は必要な行のみをロックします。
MVCC は、特定の時点でのデータのスナップショットを保存することによって実装されます。つまり、実行にどれだけ時間がかかっても、各トランザクションで表示されるデータは一貫しています。トランザクションの開始時刻に応じて、同じテーブル上の各トランザクションで同時に表示されるデータが異なる場合があります。
異なるストレージ エンジンの MVCC 実装は異なり、通常はオプティミスティック同時実行制御とペシミスティック同時実行制御です。以下では、InnoDB の動作の簡略化されたバージョンを通じて MVCC がどのように機能するかを示します。
InnoDB の MVCC は、レコードの各行の背後に 2 つの非表示列を保存することによって実装されます。これら 2 つの列のうち、1 つは行の作成時刻を保持し、もう 1 つは行の有効期限 (または削除時刻) を保持します。もちろん、保存されるのは実際の時間値ではなく、システムのバージョン番号です。新しいトランザクションが開始されるたびに、システムのバージョン番号が自動的に増加します。事務。トランザクション開始時のシステム バージョン番号はトランザクションのバージョン番号として使用され、クエリされたレコードの各行のバージョン番号と比較するために使用されます。具体的に REPEATABLE READ 分離レベルで MVCC がどのように動作するかを見てみましょう。
InnoDB は、次の 2 つの条件に基づいてレコードの各行をチェックします:
InnoDB は、バージョン番号が現在のトランザクション バージョンより前のデータ行のみを検索します (つまり、行のシステム バージョン番号がこれにより、トランザクションによって読み取られた行が、トランザクションの開始前にすでに存在していたか、トランザクション自体によって挿入または変更されたことが保証されます。
行の削除されたバージョンは、未定義であるか、現在のトランザクションのバージョン番号より大きいです。これにより、トランザクションによって読み取られた行が、トランザクションの開始前に削除されていないことが保証されます。
上記の 2 つの条件を満たすレコードのみがクエリ結果として返されます。
InnoDB は、挿入された各行の行バージョン番号として現在のシステム バージョン番号を保存します。
InnoDB は、現在のシステムのバージョン番号を、削除された各行の行削除識別子として保存します。
InnoDB は、新しいレコード行を挿入し、現在のシステム バージョン番号を行バージョン番号として保存し、現在のシステム バージョン番号を行削除識別子として元の行に保存します。
ほとんどのデータ読み取り操作をロックせずに実行できるように、これら 2 つの追加のシステム バージョン番号を保存します。この設計により、データ読み取り操作が非常にシンプルになり、パフォーマンスが非常に向上し、また、規格を満たす行のみが確実に読み取られるようになります。欠点は、レコードの各行に追加の記憶域スペース、より多くのチェック、および追加のメンテナンスが必要になることです。
MVCC は、REPEATABLE READ と READ COMMITTED の 2 つの分離レベルでのみ機能します。 READ UNCOMMITTED は、現在のトランザクション バージョンに準拠するデータ行ではなく、常に最新のデータ行を読み取るため、他の 2 つの分離レベルは MVCC と互換性がありません。 SERIALIZABLE は、読み取られたすべての行をロックします。
注: MVCC には正式な仕様がないため、各ストレージ エンジンとデータベース システムの実装は異なります。他の方法が間違っているとは誰も言えません。
MySQL のほとんどのトランザクション ストレージ エンジンの実装は、単純な行レベルのロックではありません。同時実行パフォーマンスの向上を考慮して、通常はマルチバージョン同時実行制御 (MVCC) を同時に実装します。 MySQL だけでなく、Oracle や PostgreSQL などの他のデータベース システムも MVCC を実装していますが、MVCC には統一された標準がないため、実装メカニズムが異なります。
MVCC は行レベルのロックの一種と考えることができますが、多くの場合ロック操作が回避されるため、オーバーヘッドが低くなります。実装メカニズムは異なりますが、そのほとんどはノンブロッキング読み取り操作を実装し、書き込み操作は必要な行のみをロックします。
MVCC は、特定の時点でのデータのスナップショットを保存することによって実装されます。つまり、実行にどれだけ時間がかかっても、各トランザクションで表示されるデータは一貫しています。トランザクションの開始時刻に応じて、同じテーブル上の各トランザクションで同時に表示されるデータが異なる場合があります。
異なるストレージ エンジンの MVCC 実装は異なり、通常はオプティミスティック同時実行制御とペシミスティック同時実行制御です。以下では、InnoDB の動作の簡略化されたバージョンを通じて MVCC がどのように機能するかを示します。
InnoDB の MVCC は、レコードの各行の背後に 2 つの非表示の列を保存することによって実装されます。これら 2 つの列のうち、1 つは行の作成時刻を保持し、もう 1 つは行の有効期限 (または削除時刻) を保持します。もちろん、保存されるのは実際の時間値ではなく、システムのバージョン番号です。新しいトランザクションが開始されるたびに、システムのバージョン番号が自動的に増加します。事務。トランザクション開始時のシステム バージョン番号はトランザクションのバージョン番号として使用され、クエリされたレコードの各行のバージョン番号と比較するために使用されます。具体的に REPEATABLE READ 分離レベルで MVCC がどのように動作するかを見てみましょう。
InnoDB は、次の 2 つの条件に基づいてレコードの各行をチェックします:
InnoDB は、バージョン番号が現在のトランザクション バージョンより前のデータ行のみを検索します (つまり、行のシステム バージョン番号がこれにより、トランザクションによって読み取られた行が、トランザクションの開始前にすでに存在していたか、トランザクション自体によって挿入または変更されたことが保証されます。
行の削除されたバージョンは、未定義であるか、現在のトランザクションのバージョン番号より大きいです。これにより、トランザクションによって読み取られた行が、トランザクションの開始前に削除されていないことが保証されます。
上記の 2 つの条件を満たすレコードのみがクエリ結果として返されます。
InnoDB は、挿入された各行の行バージョン番号として現在のシステム バージョン番号を保存します。
InnoDB は、現在のシステムのバージョン番号を、削除された各行の行削除識別子として保存します。
InnoDB は、新しいレコード行を挿入し、現在のシステム バージョン番号を行バージョン番号として保存し、現在のシステム バージョン番号を行削除識別子として元の行に保存します。
ほとんどのデータ読み取り操作をロックせずに実行できるように、これら 2 つの追加のシステム バージョン番号を保存します。この設計により、データ読み取り操作が非常にシンプルになり、パフォーマンスが非常に向上し、また、規格を満たす行のみが確実に読み取られるようになります。欠点は、レコードの各行に追加の記憶域スペース、より多くのチェック、および追加のメンテナンスが必要になることです。
MVCC は、REPEATABLE READ と READ COMMITTED の 2 つの分離レベルでのみ機能します。 READ UNCOMMITTED は、現在のトランザクション バージョンに準拠するデータ行ではなく、常に最新のデータ行を読み取るため、他の 2 つの分離レベルは MVCC と互換性がありません。 SERIALIZABLE は、読み取られたすべての行をロックします。
注: MVCC には正式な仕様がないため、各ストレージ エンジンとデータベース システムの実装は異なります。他の方法が間違っているとは誰も言えません。
上記は [MySQL] マルチバージョン同時実行制御の内容です。さらに関連する内容については、PHP 中国語 Web サイト (www.php.cn) に注目してください。