読み取りのMySQLは、読み出しモードと通常読み取りロックとの間に介在される:半読取り一貫性

タグ:公共号の記事


記事の声明3ロック分析を読み取るために、この記事に良いアイデアを読む前に:

スーパーロック包括的なMySQLの文の分析(パートI)

スーパーロック包括的なMySQLの文の分析(小説)

スーパーロック包括的なMySQLの文の分析(パートII)

支度をしています

物語の展開をスムーズにするためには、のは、テーブルを作成し、テーブル内の一部のレコードを挿入してみましょう、以下のSQL文は次のとおりです。

CREATE TABLE hero (
    number INT,
    name VARCHAR(100),
    country varchar(100),
    PRIMARY KEY (number),
    KEY idx_name (name)
) Engine=InnoDB CHARSET=utf8;

INSERT INTO hero VALUES
    (1, 'l刘备', '蜀'),
    (3, 'z诸葛亮', '蜀'),
    (8, 'c曹操', '魏'),
    (15, 'x荀彧', '魏'),
    (20, 's孙权', '吴');
复制代码

さてhero、次のようにテーブルの場合に記録されています:

mysql> SELECT * FROM hero;
+--------+------------+---------+
| number | name       | country |
+--------+------------+---------+
|      1 | l刘备      | 蜀      |
|      3 | z诸葛亮    | 蜀      |
|      8 | c曹操      | 魏      |
|     15 | x荀彧      | 魏      |
|     20 | s孙权      | 吴      |
+--------+------------+---------+
5 rows in set (0.01 sec)
复制代码

現象

ある:一人の学生が質問をQ&A冊子グループでREAD COMMITTED不可解な事が分離レベルで起こりました。さて、最初にすべてのテクトニクスの、現在のセッションでは、デフォルトの分離レベルに設定されるだろうREAD COMMITTED

mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
Query OK, 0 rows affected (0.00 sec)
复制代码

トランザクションは、T1最初に実行しました:

# T1中,隔离级别为READ COMMITTED
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM hero WHERE country = '魏' FOR UPDATE;
+--------+---------+---------+
| number | name    | country |
+--------+---------+---------+
|      8 | c曹操   | 魏      |
|     15 | x荀彧   | 魏      |
+--------+---------+---------+
2 rows in set (0.01 sec)
复制代码

country実装にこの文は、テーブル全体のスキャンモードスキャンクラスタ化インデックスを使用して行われなければならないので、列は、インデックス付きの列ではありませんEXPLAIN文はまた、私たちの考えていることを証明します:

mysql> EXPLAIN SELECT * FROM hero WHERE country = '魏' FOR UPDATE;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | hero  | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    5 |    20.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.02 sec)
复制代码

私たちが知っている、MySQLの文を学んだ前に、分析をロックするにはREAD COMMITTED全表スキャン方式を使用してクエリを実行した場合、次の分離レベル、InnoDBストレージエンジンは、サーバー層に記録するかどうかをテストし、各レコードプラスまともなレコードロックをオンにしますWHEREそれは、レコードのリリースロックアウトに適用されていない場合は、条件を満たしていますこの例では、使用するFOR UPDATE文を、プラスXタイプは確かに深刻なレコード・ロックです。2つだけのレコードが満たすWHERE条件ので、実際にのみ、これらの2件の最終予選レコードを追加するX型正经记录锁(つまり、あるnumber列の値815二つのレコード)。もちろん、我々は使用することができますSHOW ENGINE INNODB STATUS我々の分析を証明するためのコマンドを:

mysql> SHOW ENGINE INNODB STATUS\G
... 省略了很多内容

------------
TRANSACTIONS
------------
Trx id counter 39764
Purge done for trx's n:o < 39763 undo n:o < 0 state: running but idle
History list length 36
Total number of lock structs in row lock hash table 1
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 281479653009568, not started
0 lock struct(s), heap size 1160, 0 row lock(s)
---TRANSACTION 281479653012832, not started
0 lock struct(s), heap size 1160, 0 row lock(s)
---TRANSACTION 39763, ACTIVE 468 sec
2 lock struct(s), heap size 1160, 2 row lock(s)
MySQL thread id 19, OS thread handle 123145470611456, query id 586 localhost 127.0.0.1 root
TABLE LOCK table `xiaohaizi`.`hero` trx id 39763 lock mode IX
RECORD LOCKS space id 287 page no 3 n bits 72 index PRIMARY of table `xiaohaizi`.`hero` trx id 39763 lock_mode X locks rec but not gap
Record lock, heap no 4 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000008; asc     ;;
 1: len 6; hex 000000009b4a; asc      J;;
 2: len 7; hex 80000001d3012a; asc       *;;
 3: len 7; hex 63e69bb9e6938d; asc c      ;;
 4: len 3; hex e9ad8f; asc    ;;

Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 8000000f; asc     ;;
 1: len 6; hex 000000009b4a; asc      J;;
 2: len 7; hex 80000001d30137; asc       7;;
 3: len 7; hex 78e88d80e5bda7; asc x      ;;
 4: len 3; hex e9ad8f; asc    ;;

 ... 省略了很多内容
复制代码

どちらのidある39763取引を指しT1、それはのためにあることが分かるheap no45二つのレコード追加X型正经记录锁(lock_modeにXロックRECはなく、ギャップを )。

そして、また、分離レベルをオンにすることでREAD COMMITTED、トランザクションT2実行中:

# T2中,隔离级别为READ COMMITTED
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM hero WHERE country = '吴' FOR UPDATE;
(进入阻塞状态)
复制代码

明らかに、全表スキャンを介してこの文をロックする各クラスタ化インデックスのレコードを取得するために、実行されます。しかしので、number8のレコードがされているT1追加X型正经记录锁T2持っていると思いますが、取得することはできません、だけでブロックする余裕ができ、この時間はSHOW ENGINE INNODB STATUS、私たちの推測(のみ傍受部)であることを証明することができます:

---TRANSACTION 39764, ACTIVE 34 sec fetching rows
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1160, 1 row lock(s)
MySQL thread id 20, OS thread handle 123145471168512, query id 590 localhost 127.0.0.1 root Sending data
SELECT * FROM hero WHERE country = '吴' FOR UPDATE
------- TRX HAS BEEN WAITING 34 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 287 page no 3 n bits 72 index PRIMARY of table `xiaohaizi`.`hero` trx id 39764 lock_mode X locks rec but not gap waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000008; asc     ;;
 1: len 6; hex 000000009b4a; asc      J;;
 2: len 7; hex 80000001d3012a; asc       *;;
 3: len 7; hex 63e69bb9e6938d; asc c      ;;
 4: len 3; hex e9ad8f; asc    ;;
复制代码

見ることができますT2取得するために待機してheap noいる4レコードでX型正经记录锁(lock_modeにXロックRECはなく、ギャップ待ち)。

これらは、我々はそれを分析することができ、通常のブロッキングロジックですが、もしT2次の実行UPDATE文:

# T2中,隔离级别为READ COMMITTED
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> UPDATE hero SET name = 'xxx' WHERE country = '吴';
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0
复制代码

WTFは?そうであっても気軽に成功した実行され、ブロックされていませんか?同じWHERE条件、同じ実行計画は、どのようにSELECT ... FOR UPDATEしてUPDATEcase文が同じではありませんロック?

理由

ハハ、はい、確かに違います。実際には、MySQLは読ん文の3種類をサポートしています。

  • (:一貫した読み取りも読取り一貫性、英語名として知られている)通常の読書。

    これは、最後に追加されていない通常のSELECT文を指し、FOR UPDATEまたはLOCK IN SHARE MODESELECT文。通常の読み取りモードを実行すると、生成されReadView、読書記録するためのMVCC機構をロックされることはありません直接。

    小贴士:
    
    对于SERIALIZABLE隔离级别来说,如果autocommit系统变量被设置为OFF,那普通读的语句会转变为锁定读,和在普通的SELECT语句后边加LOCK IN SHARE MODE达成的效果一样。
    复制代码
  • ロック(:ロック読む英語名)をお読みください。

    レコードを読んで、あなたは、レコードに対応するロックを取得する必要があります前に、これはトランザクションです。もちろん、ロックの種類へのアクセスは、現在のトランザクション分離レベル、要因の実施計画、クエリや他の文に依存し、参照がなされることがあります。

  • 一貫性の半分は(:セミ一貫した読む英語名)をお読みください。

    これは、一般的な読書とロックの間に挟まれたリードリードモードです。のみでREAD COMMITTED分離レベル下(又は場合開いinnodb_locks_unsafe_for_binlogシステム変数で)使用UPDATEするときステートメントを使用します。具体的な意味は、ときということであるUPDATE文はロックがその他の事項のレコードに追加されている読み、InnoDB最新バージョンは、レコードアウトを提出読み、その後のバージョンかどうかを決定しますUPDATE文はWHERE、条件に一致しない不一致の場合その結果、次のレコードのレコードロック、、マッチングレコードが再び読み込まれ、ロックに供されている場合。この取引のように単に作るためにUPDATEブロックされた他の文を最小限にするステートメントを。

    ヒント:の半一貫性はクラスタ化インデックスをロックレコードの場合にのみ適用読んで、ロックされたセカンダリインデックスの記録には適用されません。

明らかに、取引がされているため、当社のトップはしつこいの例T2実行UPDATE文が一貫性を読んだときの半分を使用しては、判定number列の値815これら二つのレコードの最新バージョンでは、提出されcountryた列の値がどちらもあるUPDATEステートメントWHERE条件'吴'ので、それらをロックしていない、彼らに直接進んでください。

あなたが考えることを忘れないで自分の仕事の過程で学生を分析するときに、この知識は簡単に、無視することができますSemi-Consistent Readああ、コードワードは、どのようなものをダ〜、役に立つああ前方に助けて、簡単ではありません

パンフレット

MySQLはパンフレットを見るために、より高度な知識を確認したいことがあります。「MySQLはそれがどのように動作するかです:GENERから理解MySQLの」リンク冊子の主な内容は、MySQLの中核となる概念のいくつかを説明するための比較的単純な言語は、このような記録、インデックス、ページ、表スペース、クエリの最適化、取引のように、高度で、ビューの白色点からのもので、約単語の総数をロックオリジナルイラストの作品の何百もの以上40万言葉。私は主に、学習曲線ので、少しスムーズに、MySQLは先進平均プログラマの学習曲線を削減したいです-

余談

疲れ記事を書く、時にはあなたは、多くの修正の結果の後ろに実際にある非常に滑らかな読み取りを、感じます。あなたが前方に良いしてくださいヘルプを感じた場合には、ここに私のパブリック数時間から子牛を引いて、歓迎の注意程度の時間に、内側より呉服技術「我々は小さなカエルですが、」〜です非常に感謝:

おすすめ

転載: juejin.im/post/5df87b006fb9a0164b4ee6b6