MySQLの行ロック、テーブルロック、ギャップロックについて詳しく理解するための記事

準備オーケー

テーブルtb_innodb_lockを作成します

test_innodb_lockが存在する場合はテーブルを削除します。
CREATE TABLE test_innodb_lock(
    INT(11)、
    b VARCHAR(20)
)ENGINE INNODB DEFAULT charset = utf8; 
test_innodb_lock値(1、 'a');に挿入します。
test_innodb_lock値(2、 'b');に挿入します。
test_innodb_lock値(3、 'c');に挿入します。
test_innodb_lock値(4、 'd');に挿入します。
test_innodb_lock値(5、 'e');に挿入します。

インデックスを作成する

test_innodb_lock(a);にインデックスidx_lock_aを作成します。
test_innodb_lock(b);にインデックスidx_lock_bを作成します。

MySQLロックデモ

  • まず、自動コミットトランザクションを手動コミットに変更します。set autocommit=0;

  • 2つのセッションウィンドウAとBを開始し、一方がロックを取得し、もう一方が取得せずにブロックされることをシミュレートします。

行ロック(書き込みと読み取り)

  • ウィンドウの実行

test_innodb_lock set b = 'a1'を更新します。ここでa = 1;
SELECT * from test_innodb_lock;

1.png

更新された結果をウィンドウAで確認できます

  • Bウィンドウの実行

SELECT * from test_innodb_lock;

2.png

Bウィンドウでは更新された結果を確認できませんが、古いデータは引き続き表示されます。これは、Aウィンドウで実行されたSQLステートメントによってa = 1のレコードがロックされ、コミット操作が実行されなかったためです。したがって、ウィンドウBには引き続き古いデータが表示されます。これは、MySQL分離レベルでの「読み取りコミット」です。

  • ウィンドウAはコミット操作を実行します

コミット;


  • ウィンドウBクエリ

SELECT * from test_innodb_lock;

3.png

この時点で、ウィンドウBが最新のデータを読み取ったことがわかりました。

行ロック(書き込みと書き込み)

  • ウィンドウAはa = 1レコードの更新を実行します

test_innodb_lock set b = 'a2'を更新します。ここでa = 1;

このとき、コミットはなく、ウィンドウAによってロックが保持されます。

  • ウィンドウBは、a = 1のレコードも更新します

test_innodb_lock set b = 'a3'を更新します。ここでa = 1;

4.png

ご覧のとおり、ウィンドウAはまだコミットを実行しておらず、ロックを保持しているため、ウィンドウBはブロックされています。ウィンドウBは、行a = 1に記録されているロックを取得できないため、待機がブロックされています。

  • ウィンドウAはコミット操作を実行します

コミット;

  • ウィンドウBの変更

5.png

この時点でウィンドウBが正常に実行されていることがわかります。

テーブルロック

インデックスに障害が発生すると、行ロックがテーブルロックにアップグレードされます。インデックス障害の方法の1つは、インデックスを自動または手動で変更することです。フィールド自体は整数です。引用符を追加すると、文字列になります。今回はインデックスが無効になります。

  • ウィンドウAはa = 1のレコードを更新します

test_innodb_lock set b = 'a4'を更新します。ここでa = 1またはa = 2;

  • ウィンドウBはa = 2のレコードを更新します

test_innodb_lock set b = 'b1'を更新します。ここでa = 3;

6.png

このとき、ウィンドウAとウィンドウBの更新された行が異なっていても、ウィンドウAのインデックスが失敗したため、ウィンドウBがブロックされたままであることが発見されました。これにより、行ロックがテーブルロックにアップグレードされ、テーブル全体とインデックスウィンドウがロックされました。 Bはブロックされています。

  • ウィンドウAはコミット操作を実行します

コミット;

  • ウィンドウBの変更

7.png

この時点でウィンドウBが正常に実行されていることがわかります。

ギャップロック

  • ギャップロックとは

範囲条件を使用してデータを照会すると、InnoDBはこの範囲のデータをロックします。たとえば、IDが1、3、5、7の4つのデータがあり、1〜7の範囲のデータを検索します。その後、1〜7がロックされます。2、4、および6も1〜7の範囲ですが、これらのデータレコードは存在せず、これらの2、4、および6はギャップと呼ばれます。

  • ギャップロックの害

範囲を検索すると、範囲全体のすべてのデータがロックされます。この範囲に存在しないデータも無害にロックされます。たとえば、1、3、5、7に2を挿入したいのですが、今回は1 -7はロックされており、2はまったく挿入できません。一部のシナリオでは、パフォーマンスに大きな影響を与えます

  • ギャップロックデモ

まず、フィールドaの値を1、3、5、7、9に変更します。

  • ウィンドウAは、a = 1〜7の範囲でデータを更新します

test_innodb_lock set b = 'b5'を更新します。ここでa> 1およびa <7;

  • ウィンドウBはa = 2にデータを挿入します

test_innodb_lockに挿入values(2、 "b6");

8.png

このとき、1〜7の範囲のデータがギャップでロックされてロックされているため、ウィンドウBでa = 2を更新する操作が待機していることがわかります。ウィンドウAがcommitを実行した場合にのみ、ウィンドウBのa = 2で更新を成功させることができます。

行ロック分析

  • SQL分析コマンドを実行する

'innodb_row_lock%'のようなステータスを表示します。

9.png

  • Variable_nameの説明

    • Innodb_row_lock_current_waits:現在待機しているロックの数。

    • Innodb_row_lock_time:システムの起動から現在のロックまでの時間。

    • Innodb_row_lock_time_avg:毎回ロックを待機するために費やされた平均時間。

    • Innodb_row_lock_time_max:システムが起動してからロックが待機するのにかかる最長時間。

    • Innodb_row_lock_waits:システムが起動してから現在までにロックを待機した合計数。

やっと

ここを見てくれてありがとう、記事には欠陥があります、指摘することを歓迎します;それがうまく書かれていると思うなら、私に親指を上げてください。


おすすめ

転載: blog.51cto.com/14849432/2542676