mysql ロックと mvcc についての深い理解

ベース

1 ロックの説明:インタビューの必需品 - 行ロック、テーブル ロック - 楽観的ロックと悲観的ロックの違いと関係

2 mvcc の仕組みの説明(各種分離レベルの実現方法):データベース基盤 (4) Innodb MVCC 実装原理

上記 2 つの記事を読んだ直後では、多くの疑問があるかもしれませんが、私が自分で整理したいくつかの疑問を以下に示します。

1 rr レベルはどのようにしてファントム読み取りを防ぐのか

「RR」は、データベースの 4 つの標準分離レベルの 1 つである「Repeatable Read」(反復可能な読み取り)の略語で、他の 3 つは「Read Uncommitted」(コミットされていない読み取り)、「Read Committed」(コミットされた読み取り)です。 ) ) および「シリアル化可能」。分離レベルが異なれば同時実行制御も異なるため、「データの一貫性」と「同時実行パフォーマンス」の間にトレードオフが生じる可能性があります。

反復可能読み取り (Repeatable Read、RR) 分離レベルは、トランザクション内で同じデータを複数回読み取った結果の一貫性を保証します。つまり、このレベルのトランザクションでは、データを変更する他のトランザクションが認識されません。これにより、トランザクションが同じデータ行を読み取るときに、2 つの異なる時点で異なるデータが表示される「反復不可読み取り」の問題が回避されます。

ただし、RR 分離レベルであっても、「ファントム読み取り」(ファントム読み取り) 問題が発生する可能性があります。ファントム読み取りとは、トランザクション中の最初のクエリの結果と最後のクエリの結果の間の不一致を指します。この現象は、読み取られているレコードの値が他のトランザクションによって変更されることが原因ではなく、一部のレコードが他のトランザクションによって挿入または削除され、「ファントム」レコードが表示されるために発生します。

ファントム読み取りを防ぐ最も重要な方法は、最高レベルの分離レベルであるシリアル化 (シリアル化可能) を使用することです。シリアル化レベルでは、トランザクションは完全にシリアルに実行され、当然のことながらファントム リードの問題は発生しません。ただし、このレベルの分離では、同時実行パフォーマンスに大きなペナルティが伴います。

実際には、一部のデータベース システム (MySQL の InnoDB ストレージ エンジンなど) は、RR レベルでのファントム読み取りを防ぐために「Next-Key Locking」を使用します。Next-Key Locking は、クエリによってアクセスされるインデックス レコードをロックするだけでなく、インデックス内の「ギャップ」(ギャップ ロック) もロックし、他のトランザクションがその「ギャップ」レコードに新しいエントリを挿入できないようにするロック戦略です。したがって、ファントムリードの生成が回避されます。

注: Next-Key Locking 戦略では、ロックの競合が増加し、同時実行パフォーマンスが低下する可能性があります。実際のアプリケーションでは、実際の状況に応じて使用を検討する必要があります。

2ネクストロック(プロキーロック)とギャップロック(すき間ロック)

2つの違い

Next-Key Locking と Gap Locking は両方とも、Repeatable Read (RR) 分離レベルでのファントム読み取りを防ぐためのデータベース管理システム (MySQL の InnoDB エンジンなど) の技術です。これらはすべて、データの一種の「範囲ロック」を必要とします。つまり、実際にアクセスされるレコードをロックするだけでなく、レコード間の「ギャップ」もロックします。2 つの主な違いは、ロックの粒度です。

  1. Next-Key Locking : Next-Key Locking は、InnoDB のデフォルトの行ロック方法であり、行ロック (レコード ロック) とギャップ ロック (ギャップ ロック) を含む組み合わせロックです。具体的には、トランザクション T1 がインデックス レコード R にアクセスする場合、Next-Key Locking は R と R 自体の「キー値のギャップ」をロックします。このようにして、他のトランザクションが R を変更することを防ぐだけでなく、他のトランザクションが R のキーと値のギャップに新しいレコードを挿入することも防ぎます。Next-Key Locking はファントム読み取りを効果的に防止します。

  2. ギャップ ロック: ギャップ ロックは、レコード自体ではなく、インデックス レコード間のギャップのみをロックします。たとえば、トランザクション T1 がインデックス レコード R1 および R2 にアクセスする場合、ギャップ ロックは R1 と R2 の間のギャップをロックしますが、R1 と R2 自体はロックしません。これは、他のトランザクションは R1 と R2 の内容を変更できますが、R1 と R2 の間に新しいレコードを挿入できないことを意味します。ギャップ ロックは主に読み取りの一貫性を実現し、ファントム読み取りを防止するために使用されますが、反復不可能な読み取りは防止できません。

Next-Key Locking はより保守的であり、より強力なデータ一貫性保証を提供しますが、同時実行パフォーマンスが低下する可能性があります。ギャップ ロックはより緩やかで、既存のレコードを同時に変更できますが、ファントム読み取りは防止されます。実際のアプリケーションでは、特定のニーズに応じて適切なロック戦略を選択する必要があります。

キーロックを使用すると、ファントムリーディングの問題を完全に解決できます。面接官は、「本当に完璧ですか?」と尋ねました。

まとめ:安全性は完璧だが性能に欠陥がある

キー ロックを使用しても同時実行の問題がすべて解決されるわけではなく、追加のオーバーヘッドが発生するため、「完璧」という言葉は過度に断定的な表現かもしれません。

近接キー ロックは、反復読み取り分離レベルでのファントム読み取りを防止するために InnoDB によって使用されるロックで、特定の範囲に新しいレコードが挿入されるのを防ぐことができ、実際にファントム読み取りの発生を防ぐことができます。ただし、これですべての同時実行の問題が解決されるわけではありません。たとえば、キー ロックは、2 つのトランザクションの両方が同じデータを読み取り、それらを変更しようとした場合に発生する可能性がある「書き込みスキュー」問題から保護することはできません。

さらに、隣接するキー ロックによりロックのオーバーヘッドが増加し、パフォーマンスが低下する可能性があります。隣接するキー ロックでは、単一レコードだけでなくレコード範囲をロックする必要があるため、他の同時トランザクションが、ロックされたレコードと直接競合しない場合でも、レコード範囲にアクセスできなくなる可能性があります。

したがって、キー ロックはファントム読み取りの問題を効果的に解決できますが、それが「完璧」と言えるかどうかは、同時実行性とパフォーマンスに与える影響を考慮する必要があります。

繰り返し読み取りは行ロックによって保証されますか?

リピータブル リード (RR) の保証は行ロックだけに依存するわけではありません。実際のデータベース システムでは、通常、RR 分離レベルは、行ロック、ギャップ ロック (Gap Lock)、マルチバージョン同時実行制御 (MVCC、Multi-Version Concurrency Control) などを含む複数のテクノロジを組み合わせて実装する必要があります。

行ロックは、同じデータ行が他のトランザクションによって同時に変更されるのを防ぐことができますが、行ロックでは「ファントム読み取り」 (ファントム読み取り) の問題を防ぐことはできません。ファントム読み取りとは、トランザクション内で 2 つのクエリの結果に一貫性がないことを意味します。この不一致は、クエリされたレコード自体の変更によるものではなく、新しいレコードの挿入または古いレコードの削除によるものです。

ファントム読み取りの問題を解決するために、多くのデータベース システムではギャップ ロック (Gap Lock) が使用されています。ギャップ ロックは 2 つのインデックス レコード間の「ギャップ」をロックし、他のトランザクションがこのギャップに新しいレコードを挿入するのを防ぎます。

マルチバージョン同時実行制御 (MVCC) も重要なテクノロジーであり、複数の読み取りトランザクションが互いにブロックすることなく、同じデータ行に同時にアクセスできるようになります。MVCC では、各書き込み操作で新しいバージョンのデータ行が作成され、読み取り操作で適切な古いバージョンにアクセスします。このようにして、各トランザクションは、あたかもそのトランザクションだけが実行されているかのように、一貫性のあるスナップショットで実行できます。

したがって、反復読み取り分離レベルには通常、行ロック、ギャップ ロック、MVCC などの複数のテクノロジを組み合わせて実装する必要があります。

MVCC リンクからの質問

原文: MVCC はデータの履歴バージョンを保存し、比較したデータのバージョン番号に応じてデータを表示するかどうかを決定します。読み取りロックを追加せずにトランザクションの分離効果を達成でき、最終的にデータを読み取ることができます。変更すると、変更時にデータを同時に読み取ることができるため、トランザクションの同時実行パフォーマンスが大幅に向上します。

質問: 書き込み時にデータが読み取られ、読み取り時にデータが変更される場合、同時実行性の問題は発生しませんか? たとえば、2 つのリクエストが同時に受信され、1 つは読み取り、もう 1 つは書き込みですが、書き込みが最初に実行され、読み取りが最初に実行されます。は、読み取り操作の後に実行されます。この操作は、現在のバージョンのデータに対して実行する必要がありますか、それとも書き込み操作の完了後に実行する必要がありますか?

回答: マルチバージョン同時実行制御 (MVCC、マルチバージョン同時実行制御) についてのあなたの理解は正しいです。MVCC はデータの履歴バージョンを保存し、データの読み取り時に適切なバージョンを選択するため、読み取り操作と変更操作を同時に実行できるため、トランザクションの同時実行パフォーマンスが向上します。

「データは書き込まれるときに読み取られ、読み取られるときに変更されますか。同時実行の問題は発生しませんか?」という質問については、実際、MVCC モデルには、この状況に対処するための対応するルールと戦略があります。

MVCC では、各トランザクションは最初に一意のトランザクション ID (バージョン番号とも呼ばれます) を取得します。トランザクションがデータ項目を読み取ろうとする場合、トランザクションは、自身のトランザクション ID 以下のバージョン番号を持つ最新バージョンを参照します。トランザクションがデータ項目を変更する場合、トランザクションのトランザクション ID をバージョン番号とする新しいバージョンが作成されます。

したがって、あなたの質問では、2 つのトランザクション T1 (書き込み) と T2 (読み取り) があり、T1 のトランザクション ID が T2 のトランザクション ID より小さいと仮定します。T1 が最初に実行されると、新しいデータ バージョンが作成され、そのバージョン番号は T1 のトランザクション ID になります。その後、T2 が実行されると、作成される T2 のトランザクション ID 以下のバージョン番号を持つ最新バージョンが表示されます。 T1 のそのバージョンで。

このようにして、読み取り操作と変更操作が同時に実行された場合でも、各トランザクションは一貫したデータ スナップショットで実行されるため、データの一貫性の問題は発生しません。このモードでは、読み取り操作は書き込み操作をブロックせず、書き込み操作は読み取り操作をブロックしないため、高い同時実行パフォーマンスが実現します。

ただし、MVCC は同時実行パフォーマンスを向上させることができますが、同時実行の問題をすべて解決できるわけではないことに注意してください。たとえば、2 つのトランザクションが同じデータ項目を同時に変更するという問題は解決されません。通常、この状況を処理するには、ロックまたはその他の同時実行制御メカニズムを使用する必要があります。

トランザクション T1 は、保持しているバージョン データを変更しますか? この場合、T2で読み出したデータが変更されている可能性はありますか?

MVCC (Multi-Version Concurrency Control) メカニズムでは、トランザクションが書き込み操作 (データ項目の更新など) を実行すると、データ項目の新しいバージョンが作成されます (実際、新しいバージョンは依然としてデータ行、元のバージョンは、元のデータを直接変更するのではなく、アンドゥ ログ行にあります。mvcc リンク 2.4 のデモを参照してください)。新しいバージョンのバージョン番号は、トランザクションのトランザクション ID と同じです。元のデータのバージョンは保存されるため、古いバージョンのデータをまだ使用している他のトランザクションは引き続きそのデータにアクセスできます。

2 つのトランザクション T1 と T2 があり、T1 は書き込みトランザクション、T2 は読み取りトランザクションで、トランザクション ID は ID1 と ID2、ID1 < ID2 であるとします。T1 がデータ項目を変更したい場合、バージョン番号 ID1 を持つ新しいバージョンのデータを作成します。T2 がこのデータ項目を読み取ろうとすると、バージョン番号が ID2 以下の最新バージョンが表示されます。ID1 < ID2 のため、T2 は T1 によって作成された新しいバージョンを確認できます。

ただし、T2 がどのバージョンのデータを参照できるかは、T1 と T2 の開始時間と MVCC の実装戦略によって異なります。たとえば、T2 の開始時に T1 が送信されていない場合、T2 は T1 の変更前のデータ バージョンのみを確認できます。T2 の開始時に T1 がコミットしていれば、T2 は T1 の変更後のデータ バージョンを確認できます。

MVCC が保証できるのは、トランザクションの一貫したビューであることに注意してください。つまり、トランザクション内では、データが他のトランザクションによって変更されたかどうかに関係なく、表示されるデータは常に一貫しています。同時読み取りおよび書き込み操作の場合、競合が発生するかどうかは、特定の同時実行制御戦略と分離レベルによって異なります。場合によっては、同時実行性の競合を防ぐために、ロックまたはその他の同期メカニズムの使用が必要になる場合があります。

「MVCC が保証できるのは、トランザクションの一貫したビューです。つまり、トランザクション内では、データが他のトランザクションによって変更されているかどうかに関係なく、表示されるデータは常に一貫しています」を理解する方法

「MVCC が保証できるのは、トランザクションの一貫したビューです。つまり、トランザクション内では、データが他のトランザクションによって変更されているかどうかに関係なく、表示されるデータは常に一貫しています。」 この文の意味は次のとおりです。 (MVCC) メカニズムでは、各トランザクションは、トランザクションの開始時点に応じて、一貫性のある変更されていないデータ スナップショットを参照します。いわゆる「一貫性観」です。

これはどのようにして可能でしょうか? トランザクションが開始されると、一意のトランザクション ID が取得されます。これは、トランザクションが開始された時点も表します。トランザクションがデータ項目を読み取ろうとする場合、トランザクションは自身のトランザクション ID 以下のバージョン番号を持つ最新バージョンを参照します。つまり、トランザクションは開始時に存在していたデータのバージョンのみを確認でき、開始後に他のトランザクションによって作成された新しいバージョンは確認できません。トランザクションの実行中に他のトランザクションがデータを変更した場合でも、このトランザクションで表示されるデータは変更されません。

たとえば、トランザクション T1 が時点 1 に開始され、この時点で読み取られるデータ項目 A のバージョンが 1 であるとします。T1 の実行中、別のトランザクション T2 が時点 2 でデータ項目 A を変更し、バージョン 2 を作成します。ただし、データ項目 A の実際のバージョンが 2 に変更されたとしても、バージョン 1 は T1 の開始時に存在していたバージョンであるため、T1 には引き続きデータのバージョン 1 が表示されます。したがって、データがどのように変化しても、T1 が認識するデータは常に一貫しています。

この機能により、MVCC メカニズムの下で、読み取り操作が書き込み操作をブロックしないようにしたり、書き込み操作で読み取り操作をブロックしたりできるようになり、同時実行パフォーマンスが向上します。同時に、各トランザクションは一貫したデータ スナップショットで実行されるため、トランザクションの一貫性も保証されます。

ロック機構の通常の使用、書き込み操作 T1 と読み取り操作 T2 では、T1 が最初に実行される場合、T2 はブロックし、T1 の実行後に更新されたデータが読み取られるのを待つことしかできません。

ロック メカニズムを使用する場合、トランザクション (T1) がデータ項目の書き込みロックを取得すると、T1 がロックを解放するまで、このデータ項目の読み取りまたは書き込みを試行する他のすべてのトランザクション (T2 など) がブロックされます。 。したがって、この場合、T2 は実際に、T1 が実行を完了してロックを解放するまで待ってから、更新されたデータを読み取ります。

このブロッキング待機状況は、特に同時実行性の高いシステムにおいて、同時実行パフォーマンスの低下につながる可能性があります。この問題を解決する 1 つの方法は、MVCC (Multi-Version Concurrency Control) などのノンブロッキング同時実行制御メカニズムを使用することです。MVCC では、読み取り操作が書き込み操作をブロックせず、書き込み操作が読み取り操作をブロックしないため、同時実行パフォーマンスが向上します。

ただし、MVCC は同時実行パフォーマンスを向上させることができますが、複数のバージョンのデータを維持する必要性やバージョンの競合に対処する必要性など、いくつかの制限とオーバーヘッドもあります。したがって、実際のアプリケーションでは、特定のニーズと環境に応じて適切な同時実行制御戦略を選択する必要があります。

トランザクションが書き込み操作 T1 の途中で実行されたが、T2 が T1 の終了後に再度データを読み取る場合、この時点で読み取られたデータは送信後ですか、それとも送信前ですか?

マルチバージョン同時実行制御 (MVCC) モデルでは、トランザクションの開始時にトランザクション ID が取得されます。これは、トランザクションが開始された時点を表すタイムスタンプでもあります。このトランザクションによるデータのすべての読み取り操作では、開始時刻より前のデータのバージョン (つまり、トランザクション ID) のみが参照されます。

書き込みトランザクション T1 が実行中にコミットされると、データの変更により新しいバージョンのデータが生成されます。この新しいバージョンのバージョン番号は、T1 のトランザクション ID と同じになります。

読み取りトランザクション T2 の場合、T1 がコミットする前に開始されている場合、T1 が新しいデータ バージョンを送信したとしても、T2 は開始時点のデータ バージョンしか確認できません。つまり、T1 が送信する前のデータがまだ残っていると見なされます。

ただし、T1 のコミット後に T2 が開始される場合、T2 がデータを読み取ると、T1 によって送信された新しいバージョンのデータが表示されます。これは、このバージョンのデータが T2 の開始前にすでに存在していたためです。

したがって、T2 が送信後のデータを読み取るか、送信前のデータを読み取るかは、T2 の開始時刻が T1 の送信の前か後かによって決まります。これにより、MVCC モデルが一貫したビューを提供できるようになります。

読み取りビューについての質問

材料:

2.5 ビュー一致条件の読み取り:

1. データトランザクションID<up_limit_idが表示された場合

データ トランザクション ID が読み取りビューの最小アクティブ トランザクション ID より小さい場合は、現在のトランザクションが開始される前にデータがすでに存在していたことが確実であるため、データを表示できます。

2. データトランザクションID>=low_limit_idは表示されません

データ トランザクション ID が読み取りビューの現在のシステムの最大トランザクション ID より大きい場合、現在の読み取りビューが作成された後にデータが
生成されたことを意味するため、データは表示されません。

3. Up_limit_id <= データ トランザクション ID < low_limit_id は、アクティブなトランザクション セット trx_ids と一致します。

データのトランザクション ID が最小のアクティブなトランザクション ID より大きく、システムの最大のトランザクション ID 以下である場合、この状況は、現在のトランザクションの開始時にデータが送信されていない可能性があることを示します。

したがって、現時点では、データのトランザクション ID を、現在の読み取りビューのアクティブなトランザクション セット trx_ids と照合する必要があります。

ケース 1: トランザクション ID が trx_ids コレクションに存在しない場合 (読み取りビューの生成時にトランザクションがコミットされていることを意味します)、この場合のデータは表示できます。

ケース 2: トランザクション ID が trx_ids に存在する場合、読み取りビューの生成
時にデータが送信されていないことを意味しますが、データのトランザクション ID が Creator_trx_id と等しい場合は
、データが現在のトランザクションそのものと、自身で生成したデータを単体で見ることができるので、この場合はデータも表示することができます。

ケース 3: トランザクション ID が trx_ids に存在し、creator_trx_id と等しくない場合、
読み取りビューの生成時にデータが送信されておらず、独自に生成されていないことを意味するため、この場合データは表示できません。

4. 読み取りビューの条件を満たさない場合は、アンドゥログからデータを取得します

データのトランザクションIDが読み取りビュー条件を満たさない場合、アンドゥログからデータの履歴バージョンを取得し、データの履歴バージョンのトランザクション番号と読み取りビュー条件が一致するまで照合されます
。条件を満たす履歴データが見つかるか、見つからない場合は空の結果を返します。

ここでの「データ トランザクション ID」が現在の読み取りトランザクション ID を指すことはどのように理解できますか? トランザクション番号が最大ではないのはなぜですか? トランザクション ID は自動的に増加するべきではないでしょうか?

MySQL の InnoDB エンジンでは、トランザクションはマルチバージョン同時実行制御 (MVCC) メカニズムを使用します。このメカニズムでは、各データ行には、このデータ行バージョンの作成者を表すトランザクション ID が関連付けられています。トランザクションがデータ行を変更すると、新しいバージョンのデータ行が作成され、新しいバージョンのトランザクション ID がトランザクションの ID になります。したがって、「データ トランザクション ID」は、このデータ行バージョンを作成したトランザクション ID を指します。

最初の質問については、「データ トランザクション ID」は現在の読み取りトランザクションの ID ではなく、現在のバージョンのデータ行を作成したトランザクションの ID です。InnoDB エンジンはトランザクションを識別するために自動インクリメントされるトランザクション ID を使用しますが、理解する必要があるのは、各トランザクションの開始時に取得される ID がその時点での最大値であり、トランザクションによって取得される ID は、後で開始されるトランザクションは大きくなります。したがって、データ行のトランザクション ID (つまり、データ行を作成したトランザクション ID) が読み取りビューの最小アクティブ トランザクション ID より小さい場合、このデータ行は、現在のトランザクションが開始されるため、現在のトランザクションから参照できるようになります。

ここでの「データ」とは、テーブルに保存されているレコードの現在の最新バージョンを指しますか?

2 番目の質問では、「データ」とは、現在の読み取りトランザクションがアクセスしようとしているデータ行のあるバージョンを指します。MVCC では、読み取りトランザクションの開始時間と読み取りビューの内容に応じて、読み取りトランザクションで古いバージョンのデータ行が表示される可能性があるため、このバージョンはデータ行の最新バージョンではない可能性があります。これにより、MVCC は一貫したビューを提供できるようになります。

以下の場合、データトランザクションIDは事前に実行された書き込み操作である可能性がありますよね。

データトランザクションID>=low_limit_idは表示されません

データ トランザクション ID が読み取りビューの現在のシステムの最大トランザクション ID より大きい場合、現在の読み取りビューが作成された後にデータが
生成されたことを意味するため、データは表示されません。

あなたが言及したケースでは、「データトランザクションID」は確かにコミットされた書き込みトランザクションによって作成された可能性があります。データ行のトランザクション ID が読み取りビューの low_limit_id より大きい場合は、そのデータ行のバージョンが現在の読み取りトランザクションの開始後に作成されたことを意味します。したがって、書き込みトランザクションがコミットされた場合でも、このデータ バージョンは現在の読み取りトランザクションでは認識されません。これは、MVCC では、各トランザクションは開始時とその前のデータ バージョンしか認識できないためです。

この時点で、読み取りビューのアクティブなトランザクションのリストはすべて読み取りトランザクションですが、書き込みトランザクションはありますか?

読み取りビューに記録されるアクティブなトランザクションのリストには、読み取りトランザクションであるか書き込みトランザクションであるかに関係なく、読み取りトランザクションの開始時にコミットされていないすべてのトランザクションが含まれます。書き込みトランザクションの場合、後でデータを変更して新しいバージョンのデータを作成する可能性がありますが、これらの新しいバージョンのデータは現在の読み取りトランザクションでは認識されません。読み取りトランザクションの場合、データは変更されませんが、ファントム読み取り (ファントム読み取り) の問題を防ぐために、アクティブなトランザクションのリストに含める必要があります。

読み取りトランザクションを読み取りビューのアクティブ トランザクション リストに入れることで、ファントム読み取りの問題を防ぐことができるのはなぜですか?

ファントム読み取りは同時実行制御の問題です。あるトランザクションがいくつかの行を読み取り、別のトランザクションがいくつかの新しい行を挿入してから再度読み取ると、元のトランザクションは新しい「ファントム」行が出現したことを検出します。読み取りトランザクションが読み取りビューのアクティブなトランザクション リストに配置されている場合、他の同時読み取りトランザクションは書き込みトランザクションのコミットされていない変更を見ることができないため、一貫性のあるビューに新しい「ファントム」行が表示されなくなり、ファントム読み取りが防止されます。問題。これは mvcc 仕様によって決定されます。トランザクションは、バージョン番号が現在のトランザクション ID 以下のバージョン データのみを参照できます。

更新された行のトランザクション ID がアクティブなトランザクション リストにまだ存在するのはなぜですか? 行が更新されたということは、送信されたことを意味するべきではないでしょうか?

まず、ここでの「更新された行」とは、古いバージョンのデータがアンドゥログに移動され、新しいバージョンのデータが現在のデータ行を占めることを意味します。まだ送信されていないため、読み取りビュー自体がアクティブなトランザクション リストに含まれている可能性もあります。

MVCC関連のデメリット

ライトスキューとは何ですか?

書き込みスキューはより複雑な現象 (同時書き込みの問題) であり、2 つ以上のトランザクションが同じデータを同時に読み取り、読み取られたデータに基づいてトランザクションを変更することが関係します。これにより、データベースが不整合な状態になる可能性があります。たとえば、2 つのトランザクションはどちらも同じデータを読み取り、読み取ったデータに基づいて変更するため、競合やデータの不整合が発生する可能性があります。書き込みバイアスを解決するには、楽観的ロック (Optimistic Locking) または悲観的ロック (Pessimistic Locking) を使用するなど、より高度な同時実行制御メカニズムを採用する必要がある場合があります。

たとえば、
座席が 2 つあり、2 人のユーザー (トランザクション A とトランザクション B) がそれぞれ座席を予約する場合、A と B が同時に残りの座席 (2) を読み取ると、座席の数は 0 になるはずです。座席を予約することにしましたが、予約後には 1 つの座席が残っているはずだとそれぞれが考えました。ただし、両方のトランザクションが送信されると、どちらも 2 シートから 1 シートを減算するため、結果は 0 シートではなく 1 シートになります。これはいわゆるライトスキュー問題です。

リードスキューについてはどうですか?

読み取りスキュー (読み取りスキュー): 同じトランザクション内で同じデータ項目を複数回読み取ると、異なる結果が返されます。これは、読み取り/書き込みスキューで前述した「反復不能読み取り」問題です。

MVCCの欠点は何ですか?

MVCC は、複数の書き込みトランザクションの同時実行性の問題を解決できず (書き込みスキューの問題も解決できません)、読み取り/書き込みトランザクション間の同時実行性の問題を解決するためにのみ使用できます。

mvcc が複数の読み取り/書き込み複合トランザクション間、または書き込みトランザクションと書き込みトランザクション間の同時実行性の問題を解決できないのはなぜですか

取引の種類

読み取り専用、書き込み専用、読み取り/書き込み複合トランザクション。通常、mvcc は読み取り専用トランザクションと書き込み専用トランザクション、または読み取り専用トランザクションと読み取り専用トランザクション間の同時実行性の問題のみを解決できますが、複合トランザクションや書き込みトランザクション間の同時実行の問題は解決できません。専用トランザクションと書き込み専用トランザクション間の同時実行の問題

読み取り操作と書き込み操作の両方を含むトランザクションの場合、MVCC は読み取り操作も適切に処理できます。ただし、書き込み操作の場合、書き込み操作がトランザクション内の読み取り操作に依存している場合、問題が発生する可能性があります。これは、いわゆる「読み取り-書き込みスキュー」(読み取り-書き込みスキュー) です。

mvcc の書き込み-スキュー問題または書き込み-書き込みトランザクション問題を解決するにはどうすればよいですか?

1 トランザクションをシリアルに実行します (シリアル化分離レベル) が、同時実行性は非常に低くなります。
2 バージョン番号付きのオプティミスティック ロックがデータベースで使用されるため、毎回 1 つのトランザクションのみが正常に実行されます。
3 分散ロックは次の目的で使用できます。許可 データベース内のデータ行または関連ビジネスを変更するために毎回 1 つのトランザクションのみが解放されます
4 悲観的ロック: 悲観的ロックは、同時トランザクションによってデータの不整合が生じると想定しているため、他のトランザクションによる同時変更を防ぐためにデータを変更する前にロックします。銀行口座の例では、残高の確認と残高の変更の間に口座がロックされる可能性があります。このようにして、1 つのトランザクションが完了した場合にのみ、別のトランザクションを継続できるため、書き込みスキューの問題が回避されます。ただし、悲観的なロックは同時実行パフォーマンスの低下につながる可能性があります。

MVCCの適用シナリオ

Mvcc は他のロックと同様、トランザクションの分離を保証することしかできず、ビジネスに依存するトランザクションの安全性を保証することはできません。

はい、MVCC はトランザクションの分離のみを保証できます。つまり、同時に実行されるトランザクションが互いに干渉しないことです。ただし、運用上存在する依存関係は保証されません。これはビジネス ロジック レベルで処理する必要があります。たとえば、フラッシュセールのシナリオでは、MVCC が使用されている場合でも、製品が売れすぎないようにするために、楽観的ロックや悲観的ロックなどの手法を使用する必要がある場合があります。

スナップショット読み取りと現在の読み取り。seckill シナリオではどちらを使用する必要がありますか

seckill シナリオでは、通常、在庫の正確性を保証する必要があるため、現在の在庫状況をリアルタイムで知る必要があります。つまり、「現在の読み取り」が必要です。スナップショット読み取りは高い同時実行パフォーマンスを提供しますが、特定の時点でのデータ スナップショットに基づいているため、リアルタイムのインベントリ ステータスが反映されない可能性があり、高いリアルタイム パフォーマンスが必要なシナリオには適していない可能性があります。セキルなど。

スナップショットは古いデータを読み取る可能性があります。セキュリティ上の問題はありますか?

スナップショットによって読み取られたデータは古い可能性があり、シナリオによっては問題が発生する可能性があります。ライトニングディールを例に挙げると、スナップショットから読み取った在庫データに基づいて注文すると売られすぎてしまう可能性があります。たとえば、商品の実際の在庫は 1 つだけですが、複数のトランザクションのスナップショット読み取りでは、すべてのトランザクションが在庫が 1 であると認識するため、すべての商品が注文され、その結果、複数の商品が実際に販売されます。秘密の質問の一種です。

ただし、スナップショット読み取りが役に立たないというわけではありません。リアルタイム データに対する高い要件はなくても、同時実行パフォーマンスに対する高い要件がある一部のシナリオでは、スナップショット読み取りによりパフォーマンスが向上します。たとえば、ユーザーの購入履歴をカウントしたい場合、データのリアルタイム パフォーマンスはそれほど重要ではなく、スナップショット読み取りの方が同時実行パフォーマンスが向上します。

スナップショット読み取りを使用するか、現在の読み取りを使用するかについて、mysql データベースを設定できますか。粒度はテーブルまたはライブラリに対して正確ですか?

MySQL では、トランザクションごとにスナップショット読み取り (一貫性読み取りとも呼ばれます) または現在の読み取りを使用することを選択できます。これは、トランザクションの分離レベルを設定することによって実現されます。たとえば、「READ COMMITTED」分離レベルを選択した場合、各クエリは最新のデータ (現在の読み取り) を読み取ります。また、「REPEATABLE READ」分離レベルを選択すると、トランザクションの開始時にデータ スナップショットが作成され、後続のすべてのクエリはこのスナップショットに基づいてデータを読み取ります (スナップショット読み取り)。この設定はトランザクションごとであり、テーブルやライブラリに固有のものではありません。

おすすめ

転載: blog.csdn.net/yxg520s/article/details/131817634