1. ロックの粒度
上で述べたロックはすべてレコード用であり、行レベル ロックまたは行ロックと呼ぶこともできます。レコードをロックすると、このレコードにのみ影響します。このロックの粒度は比較的細かいと言えます。実際、トランザクションは、テーブル レベルでロックされます。これは当然、テーブル レベル ロックまたはテーブル ロックと呼ばれます。テーブルをロックすると、テーブル全体のレコードに影響します。ロックの粒度は比較的粗いと言えます。テーブルに追加されるロックは、共有ロック (S ロック) と排他的ロック (X ロック) に分けることもできます。
1.1、テーブルロックと行ロックの比較
ロック粒度: テーブル ロック > 行ロック
ロック効率: テーブル ロック > 行ロック
競合の可能性: テーブル ロック > 行ロック
同時実行パフォーマンス: テーブル ロック < 行ロック
1.2、テーブルにSロックを追加
トランザクションがテーブルに S ロックを追加すると、次のようになります。
他のトランザクションは引き続きテーブルの S ロックを取得できます。
他のトランザクションは、テーブル内の特定のレコードに対して S ロックを取得し続けることができます。
他のトランザクションはテーブルの X ロックを取得し続けることができません
他のトランザクションは、テーブル内の特定のレコードに対して X ロックを取得し続けることができません
1.3、テーブルに X ロックを追加します
トランザクションがテーブルに X ロックを追加する場合 (トランザクションがテーブルを独占したいことを意味します)、次のようになります。
他のトランザクションはテーブルの S ロックを取得し続けることができません
他のトランザクションはテーブル内の特定のレコードに対して S ロックを取得し続けることができません
他のトランザクションはテーブルの X ロックを取得し続けることができません
他のトランザクションは、テーブル内の特定のレコードに対して X ロックを取得し続けることができません。
テーブル レベルでの S ロックと X ロック、およびその背後にある意図ロックをよりよく理解するために、実際の例を見てみましょう。かつて人気のあったインターネット プロジェクトである Shared Office を使用してロックを説明します。
シェアオフィスには建物があり、その建物には当然多くのフロアがあります。オフィスはすべて共有で、お客様は好きなオフィスを選んで働くことができます。各フロアには顧客が同時に勤務できるため、顧客がオフィスに入るたびに、各フロアの入り口にS錠を掛けるのと同じになり、多くの顧客がオフィスに入る場合は、S錠をたくさん掛けるのと同じになります。各フロアの入り口にあるロック ロック (列レベルの S ロックと同様)。
床の張り替え、天井の張り替え、水道や電気の点検など、床のメンテナンスが行われる場合がありますが、これらのメンテナンスは同時に行うことはできません。特定のプロジェクトでフロアをオーバーホールする場合、顧客は出勤できなくなり、他のメンテナンス プロジェクトも許可されなくなります。このとき、これは X ロック (行レベルの X ロックと同様) を掛けるのと同じです。フロアのドア。
上記の 2 つのロックは床用ですが、場合によっては特別なニーズが発生することがあります。
A. Office の環境を視察したいという投資家がいます。
投資家や企業は顧客の仕事へのアクセスに影響を与えたくないが、現時点ではメンテナンス用のフロアがないため、建物のドアにSロック(テーブルレベルのSロックに似たもの)を設置することができる。現時点では:
出勤したお客様は、建物のドアにあるSロックを見てそのまま建物に入って仕事をすることができます。
修理業者は、建物の入り口にあるSロックを見つけると、まず建物の入り口で待機し、投資家が帰ると、建物のSロックを外してメンテナンスのため建物に入ります。
B. 会社は家主と条件を交渉する必要があります。
現時点では、建物内で作業床を使用することは許可されておらず、床のメンテナンスも許可されていません。したがって、建物の入り口に X ロック (テーブルレベルの X ロックと同様) を設置できます。現時点では:
出勤したお客様は、ビルの入り口にXロックがあるので、ビルの入り口で待機し、条件交渉ができたら、ビルのXロックを外し、建物に入ると、仕事。
修理業者は建物の入り口にあるX錠を見つけると、まず建物の入り口で待機し、交渉が終わったら建物のX錠を外してメンテナンスのため建物に入ります。
2. インテントロック
しかし、上の例には 2 つの問題があります。
建物全体を施錠したい場合は、まず建物内にメンテナンス中のフロアがないことを確認する必要があり、メンテナンス中のフロアがある場合は、メンテナンスが完了するまで待ってから建物を施錠する必要があります。全体。
建物全体を X ロックしたい場合は、まず建物内にオフィス フロアやメンテナンス中のフロアがないことを確認する必要があります。オフィス フロアやメンテナンス中のフロアがある場合は、すべてのオフィスの学生が退室するまで待つ必要があります。建物全体の X ロックは、床を修理して立ち去った後にのみ施錠できます。
建物全体をロックする場合 (テーブル ロック)、建物内のいずれかのフロアがロックされているかどうか (行ロック) はどうすればわかりますか? 各階のドアが施錠されているかを順番に確認しますか?それでは、この効率は遅すぎます。そこで、InnoDB はインテンション ロック (英語名: Intention Locks) を提案しました。
Intention Shared Lock、英語名:Intention Shared Lock、略してISロック。トランザクションがレコードに S ロックを追加しようとしているときは、最初にテーブル レベルで IS ロックを追加する必要があります。
Intention Exclusive Lock、英語名:Intention Exclusive Lock、IXロックと呼ばれます。トランザクションがレコードに X ロックを追加する場合、最初にテーブル レベルで IX ロックを追加する必要があります。
視点は建物と床に戻ります。
顧客がフロアに出勤する場合、まず建物全体のドアにISロック(テーブルレベルロック)を取り付け、次にフロアのドアにSロック(列ロック)を取り付けます。
保守員がメンテナンスのためにフロアに行く場合、まず建物全体のドアにIXロック(テーブルレベルロック)を取り付け、次にフロアのドアにXロック(列ロック)を取り付けます。
後:
投資家がその建物を訪問したい場合、つまり建物の入り口にS錠(テーブル錠)を設置したい場合、まず建物の入り口にIX錠があるかどうかを確認する必要があります。ロックは、IX ロックが削除された後にのみ建物全体に追加できます。
建物に占有する条件がある場合、つまり建物のドアの前にX錠(テーブル錠)を設置したい場合は、まず建物のドアにIS錠かIX錠があるかを確認する必要があります。 Xロックは、お客様が工事やメンテナンスを終えてISロック、IXロックを取り外した後にのみ建物全体に追加することができます。
注: 顧客が建物のドアに IS ロックを追加する場合、建物のドアに IX ロックがあるかどうかは気にしませんが、保守作業員が建物のドアに IX ロックを追加する場合は、気にします。建物のドアに IS ロックがあるか、他の IX ロックがあるかは関係ありません。IS ロックと IX ロックは、現時点で建物内に占有フロアがあるかどうかを判断するためにのみ使用されます。つまり、建物に S ロックまたは X ロックを追加するときに使用されます。
要約: IS ロックと IX ロックはテーブル レベルのロックであり、後でテーブル レベルの S ロックと X ロックを追加するときにテーブル内のレコードがロックされているかどうかを迅速に判断し、トラバーサルによるテーブルの表示を避けるためにのみ提案されています。にはロックされたレコードはありません。つまり、ISロックとIXロックは互換性があり、IXロックとIXロックは互換性があります。テーブルを描いて、さまざまなロックの互換性をテーブル レベルで確認してみましょう。
互換性 | バツ | IX | S | は |
---|---|---|---|---|
バツ | 非互換 | 非互換 | 非互換 | 非互換 |
IX | 非互換 | 非互換 | ||
S | 非互換 | 非互換 | ||
は | 非互換 |
ロックの組み合わせ: (インテント ロックには行ロックがありません)
組み合わせ | バツ | IX | S | は |
---|---|---|---|---|
テーブルロック | もつ | もつ | もつ | もつ |
行ロック | もつ | もつ |
3. MySQL の行ロックとテーブル ロック
MySQL は複数のストレージ エンジンをサポートしており、ストレージ エンジンが異なればサポートされるロックも異なります。もちろん、私たちは依然として InnoDB ストレージ エンジンのロックに焦点を当てており、他のストレージ エンジンについては単に確認するだけです。
3.1、他のストレージエンジンのロック
MyISAM、MEMORY、MERGE などのストレージ エンジンの場合、テーブル レベルのロックのみがサポートされ、これらのエンジンはトランザクションをサポートしないため、これらのストレージ エンジンを使用するロックは通常、現在のセッション用です。たとえば、セッション 1 のテーブルに対して SELECT 操作を実行することは、テーブル レベルの S ロックをテーブルに追加することと同等です。SELECT 操作が完了していない場合、セッション 2 のテーブルに対して UPDATE 操作を実行することは、テーブルの X ロックの場合、この操作はセッション 1 の SELECT 操作が完了するまでブロックされます。テーブル レベルの S ロックが解放された後、セッション 2 のテーブルに対する UPDATE 操作は引き続き X ロックを取得できます。特定の更新ステートメントを実行します。
MyISAM、MEMORY、MERGE などのストレージ エンジンを使用するテーブルでは、同時に 1 つのセッションのみがテーブルに書き込むことができるため、これらのストレージ エンジンは、実際には読み取り専用、または読み取りがほとんどの操作、またはシングル ユーザー シナリオに最適に使用されます。さらに、MyISAM ストレージ エンジンには同時挿入と呼ばれる機能があり、MyISAM テーブルの読み取り時にレコードの同時挿入をサポートし、挿入速度を一部向上させることができます。同時挿入の詳細については、ドキュメントを参照してください。
3.2、InnoDB ストレージ エンジンのロック
InnoDB ストレージ エンジンは、テーブル ロックと行ロックの両方をサポートします。テーブル ロックは実装が簡単で、占有するリソースも少なくなりますが、粒度は非常に粗く、少数のレコードのみをロックする必要がある場合もありますが、テーブル ロックの使用はテーブル内のすべてのレコードをロックすることと同等であるため、パフォーマンスは比較的劣ります。行ロックの粒度が細かくなり、より正確な同時実行制御が可能になります。以下で詳しく見てみましょう。
3.2.1、InnoDB のテーブルレベルのロック
3.2.1.1、テーブルレベルの S ロック、X ロック、およびメタデータ ロック
テーブルに対して SELECT、INSERT、DELETE、および UPDATE ステートメントを実行する場合、InnoDB ストレージ エンジンはテーブル レベルの S ロックまたは X ロックをテーブルに追加しません。
さらに、ALTER TABLE や DROP TABLE などの一部の DDL ステートメントがテーブルで実行されると、他のトランザクションは、このテーブルでの SELECT、INSERT、DELETE、UPDATE などのステートメントの同時実行をブロックします。テーブルに対する SELECT、INSERT、DELETE、および UPDATE ステートメントを実行すると、他のセッションでこのテーブルに対して DDL ステートメントを実行することもブロックされます。このプロセスは実際には、サーバー層でいわゆるメタデータ ロック (英語名: Metadata Locks、略して MDL) を使用して実装されます。一般に、テーブル レベルの S ロックや InnoDB ストレージ エンジン自体によって提供されるロックは、中古のXロックです。
実際、InnoDB ストレージ エンジンによって提供されるテーブル レベルの S ロックまたは X ロックは非常に無味で、クラッシュ回復時などの特殊な場合にのみ使用されます。ただし、手動で取得することは可能です。たとえば、システム変数 autocommit=0 および innodb_table_locks=1 の場合、InnoDB ストレージ エンジンによって提供されるテーブル t の S ロックまたは X ロックを手動で取得するには、次のように記述できます。
LOCK TABLES t READ: InnoDB ストレージ エンジンは、テーブル レベルの S ロックをテーブル t に追加します。
LOCK TABLES t WRITE: InnoDB ストレージ エンジンは、テーブル レベルの X ロックをテーブル t に追加します。
InnoDB ストレージ エンジンを使用するテーブルで LOCK TABLES などの手動ロック テーブル ステートメントを使用することは避けてください。追加の保護は提供されず、同時実行機能が低下するだけです。
3.2.1.2、テーブルレベルの IS ロックと IX ロック
InnoDB ストレージ エンジンを使用してテーブルのいくつかのレコードに S ロックを追加する前に、テーブル レベルで IS ロックを追加する必要があります。InnoDB ストレージ エンジンを使用してテーブルのいくつかのレコードに X ロックを追加する前に、 IX は最初にテーブル レベルでロックします。
IS ロックと IX ロックの役割は、テーブル レベルの S ロックと X ロックを追加するときに、テーブル内にロックされたレコードがあるかどうかを確認するためにトラバーサルを使用することを回避することだけです。インテント ロックを手動で追加することはできません。InnoDB ストレージ エンジンのみが単独で追加できます。
3.2.1.3、テーブルレベルのAUTO-INCロック
MySQL を使用するプロセスでは、テーブルの特定の列に AUTO_INCREMENT 属性を追加することができ、レコードを挿入するときにその列の値が指定されていない場合があり、システムが自動的に増分値をその列に割り当てます。システムは AUTO_INCREMENT のこの自動変更を実現します。増分列割り当てには 2 つの主な原則があります。
1. AUTO-INC ロックを採用する、つまり、INSERT ステートメントの実行時にテーブル レベルで AUTO-INC ロックを追加し、挿入される各レコードの AUTO_INCREMENT 変更列に増分値を割り当てます。 , 次にAUTO-INCロックを解除します。このようなトランザクションが AUTO-INC ロックを保持している場合、他のトランザクションの挿入ステートメントはブロックされ、ステートメントに割り当てられる増分値が連続的であることが保証されます。
挿入ステートメントが実行前に挿入するレコードの数を決定できない場合 (挿入されるレコードの数を予測することが不可能な場合)、たとえば、INSERT ... SELECT、REPLACE ... SELECT、LOAD DATA などの挿入ステートメントを使用します。 , 一般的には、AUTO-INC ロックを使用して、AUTO_INCREMENT によって変更された列に対応する値を生成します。
2. 軽量ロックを使用して、挿入ステートメントの AUTO_INCREMENT 変更列の値を生成するときに軽量ロックを取得し、この挿入ステートメントに必要な AUTO_INCREMENT 列の値を生成して、軽量ロックを設定します。ロックは解放されますが、挿入ステートメント全体が実行されるまでロックを解放する必要はありません。
insert ステートメントが実行前に挿入するレコードの数を決定できる場合、たとえば、上記のテーブル t に関する例では、ステートメントが実行される前に 2 つのレコードを挿入することを決定でき、通常は軽量の列への値の割り当てを使用します。ロックの形式で AUTO_INCREMENT によって変更されます。この方法により、テーブルのロックが回避され、挿入のパフォーマンスが向上します。
InnoDB は、AUTO_INCREMENT によって変更されたカラムに値を割り当てるために上記 2 つのメソッドのどちらを使用するかを制御する innodb_autoinc_lock_mode というシステム変数を提供します。innodb_autoinc_lock_mode の値が 0 の場合、AUTO-INC ロックが使用されます。 innodb_autoinc_lock_mode が 2 の場合、軽量ロックが常に使用されます。 innodb_autoinc_lock_mode の値が 1 の場合、2 つの方法が混合されます (つまり、挿入されたレコードの数が決定されている場合は軽量ロックが使用され、不確実な場合は AUTO-INC ロックが使用されます) )。
ただし、innodb_autoinc_lock_mode の値が 2 の場合、AUTO_INCREMENT によって変更された列の異なるトランザクションの挿入ステートメントによって生成された値が交差する可能性があり、マスター/スレーブ レプリケーションのシナリオでは安全ではありません。
'innodb_autoinc_lock_mode' のような変数を表示します。
MySQL5.7.X ではデフォルトは 1 です。
3.2.2、InnoDB の行レベルのロック
行ロック (レコード ロックとも呼ばれる) は、その名前が示すとおり、レコードに追加されるロックです。ただし、このレコードはインデックス上のインデックス項目のロックを参照していることに注意してください。InnoDB の行ロック実装機能は、インデックス条件を通じてデータが取得される場合にのみ InnoDB が行レベルのロックを使用し、それ以外の場合は InnoDB がテーブル ロックを使用することを意味します。
主キー インデックス、一意のインデックス、または通常のインデックスのいずれを使用する場合でも、InnoDB は行ロックを使用してデータをロックします。
行ロックは、実行プランが実際にインデックスを使用する場合にのみ使用できます:条件でインデックス フィールドが使用されている場合でも、データの取得にインデックスを使用するかどうかは、さまざまな実行プランのコストを判断して MySQL によって決定されます。フル テーブル スキャンが効率的であること たとえば、一部の非常に小さなテーブルの場合、インデックスは使用されず、この場合、InnoDB は行 ロックの代わりにテーブル ロックを使用します。
同時に、等価条件ではなく範囲条件を使用してデータを取得し、ロックを要求すると、InnoDB は条件を満たす既存のデータ レコードのインデックス項目をロックします。
ただし、行ロックであっても、InnoDB はさまざまなタイプに分かれています。つまり、同じレコードに行ロックを付加しても、種類が異なれば効果も異なります。前の教師を使用し、インデックスを追加し、いくつかのレコードを挿入します。
INDEX `idx_number`(`number`)
一般的に使用される行ロックのタイプを見てみましょう。
レコードロック
1つのレコードのみをロックすることをレコードロックとも言い、正式な型名はLOCK_REC_NOT_GAPです。たとえば、数値 6 のレコードにレコード ロックを追加する概略図は次のとおりです。
レコード ロックは、S ロックと X ロックに分割されます。トランザクションがレコードの S タイプのレコード ロックを取得すると、他のトランザクションはそのレコードの S タイプのレコード ロックを引き続き取得できますが、X タイプのレコード ロックを取得し続けることはできません。レコード ロック。 ;トランザクションがレコードの X タイプ レコード ロックを取得すると、他のトランザクションはそのレコードの S タイプ レコード ロックも X タイプ レコード ロックも取得し続けることはできません。
ギャップロック
MySQL は REPEATABLE READ 分離レベルでのファントム読み取りの問題を解決できると言われていますが、MVCC スキームを使用するかロック スキームを使用することで解決できる 2 つの解決策があります。しかし、ロック ソリューションを使用する場合には問題があります。つまり、トランザクションが初めて読み取り操作を実行するとき、それらのファントム レコードはまだ存在せず、これらのファントム レコードにレコード ロックを追加することはできません。InnoDB は、Gap Locks と呼ばれるロックを提案しています。正式な型名は LOCK_GAP です。略してギャップ ロックと呼ぶこともできます。
ギャップ ロックは本質的にインデックスの前後のギャップをロックするものであり、インデックス自体をロックするものではありません。
セッション 1 はトランザクションを開始して実行します
始める; 教師セットのドメイン = 'JVM' 番号 = '6' を更新します。
2~6と6~10の間にロックがあります。
図に示すように、レコード 2 ~ 6 と 6 ~ 10 にはギャップ ロックが追加されています。これは、他のトランザクションがこのレコードの前後のギャップに新しいレコードを挿入できないことを意味します。
始める; 教師に挿入 value(7,'晁','docker');
なぜ挿入できないのでしょうか?レコード (7,'chao','docker') を挿入する場合、インデックス idx_number がちょうど 6 と 10 の間に収まるため、ロックされており、当然挿入は許可されません。
しかし、SQL ステートメントが insert into Teacher value(70,'Chao','docker'); になった場合、挿入できるでしょうか。
もちろん、レコード 70 はロックされた範囲内にないため、可能です。