占座 ...
Preface Last night one buddy in tech wechat group asked "what's intention locks of InnoDB?"Thus,I'm gonna say someting about it.As we all know,there're various types of lock in InnoDB engine such as record locks,gap locks,next key locks and so forth.Intention locks is another kind of granularity of lock of InnoDB. Introduce 1. Intention Locks Intention locks of InnoDB are table-level locks.It's generated to indicate which type of lock relevant to a certain row in which the transaction will involve(shared or exclusive lock).It seems like that one guy is booking a ticket of the train to somewhere while the ticket system broadcasts there's a guy mean to ocuppy a seat of certain compartment in the train.But it does not block the action of booking ticket on the same train from another guy at the same time(another intention lock).That is,intention locks does not block each other at all only if you are modify the same row(booking the same seat).It's the effect of exclusive lock instead of intention lock. There're two kinds of intention locks in InnoDB:
- Intention shared lock(IS): It indicates that a transaction is setting(or going to set) a shared lock on several rows for shared query operations.
- Intention exclusive lock(IX): It indicates that a transaction is setting(or going to set) a exclusive lock on several rows for exclusive modification operations.
X | IX | S | IS | |
---|---|---|---|---|
X |
Conflict | Conflict | Conflict | Conflict |
IX |
Conflict | Compatible | Conflict | Compatible |
S |
Conflict | Conflict | Compatible | Compatible |
IS |
Conflict | Compatible | Compatible | Compatible |
What we can see is that intention locks does not conflict themselves and always be compatible.In most scenarios,Intention locks do not block other transactions except for operation like "lock table ... writ;".The purpose of intention locks is to tell Innodb that someone is gonna add a lock on those relevant rows(for later reading or modifying) in a target table. 2. Insert Intention Locks Now we've known clearly about intention locks,but what's the insert intention locks?Are the intention locks relevant with insert operations?Almost,it actually related to gap lock generated by insert operation.It indicates that transactions of insert do not need to wait for each other if they are not inserting at same position within the gap when they later get the exclusive locks on those inserted rows . Examples 1. Intention locks test in the same session with "innodb_status_output_locks=off".
1 zlm@192.168.56.100:3306 [zlm]>select @@transaction_isolation; 2 +-------------------------+ 3 | @@transaction_isolation | 4 +-------------------------+ 5 | REPEATABLE-READ | 6 +-------------------------+ 7 1 row in set (0.00 sec) 8 9 zlm@192.168.56.100:3306 [zlm]>show variables like '%status%'; 10 +----------------------------+-------+ 11 | Variable_name | Value | 12 +----------------------------+-------+ 13 | innodb_status_output | ON | //If set "on",it prints innodb status into error log and refresh every 20s by default. 14 | innodb_status_output_locks | OFF | //If set "off",there're no intention locks in result of "show engine innodb status;". 15 +----------------------------+-------+ 16 2 rows in set (0.01 sec) 17 18 zlm@192.168.56.100:3306 [(none)]>select @@autocommit; 19 +--------------+ 20 | @@autocommit | 21 +--------------+ 22 | 1 | //If does not specify "begin" or "start transaction" to explicitly generate a transaction,it commits after typing enter. 23 +--------------+ 24 1 row in set (0.00 sec) 25 26 zlm@192.168.56.100:3306 [zlm]>show create table t\G 27 *************************** 1. row *************************** 28 Table: t 29 Create Table: CREATE TABLE `t` ( 30 `id` int(11) NOT NULL, 31 `name` char(10) DEFAULT NULL, 32 KEY `id` (`id`) 33 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 34 1 row in set (0.01 sec) 35 36 zlm@192.168.56.100:3306 [zlm]>begin;select * from t where name = 'aaa' lock in share mode; 37 Query OK, 0 rows affected (0.00 sec) 38 39 +----+------+ 40 | id | name | 41 +----+------+ 42 | 1 | aaa | 43 +----+------+ 44 1 row in set (0.00 sec) 45 46 zlm@192.168.56.100:3306 [zlm]>select * from t for update; 47 +----+------+ 48 | id | name | 49 +----+------+ 50 | 1 | aaa | 51 | 2 | bbb | 52 | 4 | ccc | 53 | 6 | fff | 54 +----+------+ 55 4 rows in set (0.00 sec) 56 57 [root@zlm1 03:41:54 /data/mysql/mysql3306/data] 58 #echo '' > error.log 59 60 [root@zlm1 03:42:04 /data/mysql/mysql3306/data] 61 #tail -f error.log 62 63 64 ... 65 ------------ 66 TRANSACTIONS 67 ------------ 68 Trx id counter 2996009 69 Purge done for trx's n:o < 2996003 undo n:o < 0 state: running but idle 70 History list length 12 71 LIST OF TRANSACTIONS FOR EACH SESSION: 72 ---TRANSACTION 2996008, ACTIVE 83 sec 73 4 lock struct(s), heap size 1136, 10 row lock(s) 74 MySQL thread id 210, OS thread handle 140311521974016, query id 8335 zlm1 192.168.56.100 zlm 75 ... 76 77 ---------------------------- 78 END OF INNODB MONITOR OUTPUT 79 ============================ 80 ^C 81 82 //There're no intention locks at all.
2. Intention locks test in the same session with "innodb_status_output_locks=on".
1 zlm@192.168.56.100:3306 [zlm]>set @@global.innodb_status_output_locks=on; 2 Query OK, 0 rows affected (0.00 sec) 3 4 zlm@192.168.56.100:3306 [zlm]>exit 5 Bye 6 7 [root@zlm1 03:44:23 /data/mysql/mysql3306/data] 8 #mysql 9 Welcome to the MySQL monitor. Commands end with ; or \g. 10 Your MySQL connection id is 217 11 Server version: 5.7.21-log MySQL Community Server (GPL) 12 13 Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. 14 15 Oracle is a registered trademark of Oracle Corporation and/or its 16 affiliates. Other names may be trademarks of their respective 17 owners. 18 19 Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. 20 21 zlm@192.168.56.100:3306 [(none)]>select @@transaction_isolation; 22 +-------------------------+ 23 | @@transaction_isolation | 24 +-------------------------+ 25 | REPEATABLE-READ | 26 +-------------------------+ 27 1 row in set (0.00 sec) 28 29 zlm@192.168.56.100:3306 [(none)]>select @@global.innodb_status_output_locks; 30 +-------------------------------------+ 31 | @@global.innodb_status_output_locks | 32 +-------------------------------------+ 33 | 1 | 34 +-------------------------------------+ 35 1 row in set (0.00 sec) 36 37 zlm@192.168.56.100:3306 [(none)]>select @@global.innodb_status_output; 38 +-------------------------------+ 39 | @@global.innodb_status_output | 40 +-------------------------------+ 41 | 1 | 42 +-------------------------------+ 43 1 row in set (0.00 sec) 44 45 zlm@192.168.56.100:3306 [(none)]>select @@autocommit; 46 +--------------+ 47 | @@autocommit | 48 +--------------+ 49 | 1 | 50 +--------------+ 51 1 row in set (0.00 sec) 52 53 zlm@192.168.56.100:3306 [(none)]>use zlm 54 Reading table information for completion of table and column names 55 You can turn off this feature to get a quicker startup with -A 56 57 Database changed 58 zlm@192.168.56.100:3306 [zlm]>begin;select * from t where name = 'aaa' lock in share mode; 59 Query OK, 0 rows affected (0.00 sec) 60 61 +----+------+ 62 | id | name | 63 +----+------+ 64 | 1 | aaa | 65 +----+------+ 66 1 row in set (0.00 sec) 67 68 zlm@192.168.56.100:3306 [zlm]>select * from t for update; 69 +----+------+ 70 | id | name | 71 +----+------+ 72 | 1 | aaa | 73 | 2 | bbb | 74 | 4 | ccc | 75 | 6 | fff | 76 +----+------+ 77 4 rows in set (0.00 sec) 78 79 [root@zlm1 03:42:09 /data/mysql/mysql3306/data] 80 #tail -f error.log 81 82 ... 83 ------------ 84 TRANSACTIONS 85 ------------ 86 Trx id counter 2996010 87 Purge done for trx's n:o < 2996003 undo n:o < 0 state: running but idle 88 History list length 12 89 LIST OF TRANSACTIONS FOR EACH SESSION: 90 ---TRANSACTION 2996009, ACTIVE 29 sec 91 4 lock struct(s), heap size 1136, 10 row lock(s) 92 MySQL thread id 217, OS thread handle 140311415838464, query id 8738 zlm1 192.168.56.100 zlm 93 TABLE LOCK table `zlm`.`t` trx id 2996009 lock mode IS //Here's an "IS" intention lock generated by "select ... lock in share mode;" operation. 94 RECORD LOCKS space id 175 page no 3 n bits 72 index GEN_CLUST_INDEX of table `zlm`.`t` trx id 2996009 lock mode S //Here's a "S" shared lock of records. 95 Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 96 0: len 8; hex 73757072656d756d; asc supremum;; 97 98 Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 99 0: len 6; hex 000000000700; asc ;; 100 1: len 6; hex 0000002db708; asc - ;; 101 2: len 7; hex a8000002610110; asc a ;; 102 3: len 4; hex 80000001; asc ;; 103 4: len 10; hex 61616120202020202020; asc aaa ;; 104 105 Record lock, heap no 3 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 106 0: len 6; hex 000000000701; asc ;; 107 1: len 6; hex 0000002db708; asc - ;; 108 2: len 7; hex a800000261011f; asc a ;; 109 3: len 4; hex 80000002; asc ;; 110 4: len 10; hex 62626220202020202020; asc bbb ;; 111 112 Record lock, heap no 4 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 113 0: len 6; hex 000000000702; asc ;; 114 1: len 6; hex 0000002db708; asc - ;; 115 2: len 7; hex a800000261012e; asc a .;; 116 3: len 4; hex 80000004; asc ;; 117 4: len 10; hex 63636320202020202020; asc ccc ;; 118 119 Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 120 0: len 6; hex 000000000703; asc ;; 121 1: len 6; hex 0000002db721; asc - !;; 122 2: len 7; hex 360000012c2a35; asc 6 ,*5;; 123 3: len 4; hex 80000006; asc ;; 124 4: len 10; hex 66666620202020202020; asc fff ;; 125 126 TABLE LOCK table `zlm`.`t` trx id 2996009 lock mode IX //Here's an "IX" intertion lock generated by "select ... for update;" operation. 127 RECORD LOCKS space id 175 page no 3 n bits 72 index GEN_CLUST_INDEX of table `zlm`.`t` trx id 2996009 lock_mode X //Here's a "X" exclusive lock of records. 128 Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 129 0: len 8; hex 73757072656d756d; asc supremum;; 130 131 Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 132 0: len 6; hex 000000000700; asc ;; 133 1: len 6; hex 0000002db708; asc - ;; 134 2: len 7; hex a8000002610110; asc a ;; 135 3: len 4; hex 80000001; asc ;; 136 4: len 10; hex 61616120202020202020; asc aaa ;; 137 138 Record lock, heap no 3 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 139 0: len 6; hex 000000000701; asc ;; 140 1: len 6; hex 0000002db708; asc - ;; 141 2: len 7; hex a800000261011f; asc a ;; 142 3: len 4; hex 80000002; asc ;; 143 4: len 10; hex 62626220202020202020; asc bbb ;; 144 145 Record lock, heap no 4 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 146 0: len 6; hex 000000000702; asc ;; 147 1: len 6; hex 0000002db708; asc - ;; 148 2: len 7; hex a800000261012e; asc a .;; 149 3: len 4; hex 80000004; asc ;; 150 4: len 10; hex 63636320202020202020; asc ccc ;; 151 152 Record lock, heap no 5 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 153 0: len 6; hex 000000000703; asc ;; 154 1: len 6; hex 0000002db721; asc - !;; 155 2: len 7; hex 360000012c2a35; asc 6 ,*5;; 156 3: len 4; hex 80000006; asc ;; 157 4: len 10; hex 66666620202020202020; asc fff ;; 158 ... 159 160 ---------------------------- 161 END OF INNODB MONITOR OUTPUT 162 ============================ 163 ^C 164 165 //We've got an "IS" intention loc,an "IX" intention lock,four "S" locks and four "X" locks. 166 //Why does "slect ... where name = 'aaa' lock in share mode;" operation holds four "S" locks while we just specify one line?'cause "name" column does not has index key on it. 167 //Therefore,if we need to observe the intention locks.The variable of "innodb_status_output_locks" should be set "on".
3. Intention locks test between two sessions.
1 //Session 1: 2 zlm@192.168.56.100:3306 [zlm]>select @@global.innodb_status_output; 3 +-------------------------------+ 4 | @@global.innodb_status_output | 5 +-------------------------------+ 6 | 1 | 7 +-------------------------------+ 8 1 row in set (0.00 sec) 9 10 zlm@192.168.56.100:3306 [zlm]>select @@autocommit; 11 +--------------+ 12 | @@autocommit | 13 +--------------+ 14 | 1 | 15 +--------------+ 16 1 row in set (0.00 sec) 17 18 zlm@192.168.56.100:3306 [zlm]>begin;select * from t where name = 'aaa' lock in share mode; 19 Query OK, 0 rows affected (0.00 sec) 20 21 +----+------+ 22 | id | name | 23 +----+------+ 24 | 1 | aaa | 25 +----+------+ 26 1 row in set (0.00 sec) 27 28 //Session 2: 29 zlm@192.168.56.100:3306 [(none)]>select @@global.innodb_status_output_locks; 30 +-------------------------------------+ 31 | @@global.innodb_status_output_locks | 32 +-------------------------------------+ 33 | 1 | 34 +-------------------------------------+ 35 1 row in set (0.00 sec) 36 37 zlm@192.168.56.100:3306 [(none)]>select @@global.innodb_status_output; 38 +-------------------------------+ 39 | @@global.innodb_status_output | 40 +-------------------------------+ 41 | 1 | 42 +-------------------------------+ 43 1 row in set (0.00 sec) 44 45 zlm@192.168.56.100:3306 [(none)]>select @@autocommit; 46 +--------------+ 47 | @@autocommit | 48 +--------------+ 49 | 1 | 50 +--------------+ 51 1 row in set (0.00 sec) 52 53 zlm@192.168.56.100:3306 [(none)]>begin;select * from t for update; 54 Query OK, 0 rows affected (0.00 sec) 55 56 ERROR 1046 (3D000): No database selected 57 zlm@192.168.56.100:3306 [(none)]>begin;select * from zlm.t for update; 58 Query OK, 0 rows affected (0.00 sec) 59 60 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction //Wait for 50 seconds(by default) then becomes timeout. 61 zlm@192.168.56.100:3306 [(none)]> 62 63 //Check the lock information in error log. 64 [root@zlm1 04:02:10 /data/mysql/mysql3306/data] 65 #tail -f error.log 66 67 ... 68 ------------ 69 TRANSACTIONS 70 ------------ 71 Trx id counter 2996011 72 Purge done for trx's n:o < 2996003 undo n:o < 0 state: running but idle 73 History list length 12 74 LIST OF TRANSACTIONS FOR EACH SESSION: 75 ---TRANSACTION 2996010, ACTIVE 3 sec starting index read 76 mysql tables in use 1, locked 1 77 LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s) 78 MySQL thread id 244, OS thread handle 140311521974016, query id 9672 zlm1 192.168.56.100 zlm Sending data 79 select * from zlm.t for update 80 ------- TRX HAS BEEN WAITING 3 SEC FOR THIS LOCK TO BE GRANTED: 81 RECORD LOCKS space id 175 page no 3 n bits 72 index GEN_CLUST_INDEX of table `zlm`.`t` trx id 2996010 lock_mode X waiting 82 Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 83 0: len 6; hex 000000000700; asc ;; 84 1: len 6; hex 0000002db708; asc - ;; 85 2: len 7; hex a8000002610110; asc a ;; 86 3: len 4; hex 80000001; asc ;; 87 4: len 10; hex 61616120202020202020; asc aaa ;; 88 89 ------------------ 90 TABLE LOCK table `zlm`.`t` trx id 2996010 lock mode IX 91 RECORD LOCKS space id 175 page no 3 n bits 72 index GEN_CLUST_INDEX of table `zlm`.`t` trx id 2996010 lock_mode X waiting 92 Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 93 0: len 6; hex 000000000700; asc ;; 94 1: len 6; hex 0000002db708; asc - ;; 95 2: len 7; hex a8000002610110; asc a ;; 96 3: len 4; hex 80000001; asc ;; 97 4: len 10; hex 61616120202020202020; asc aaa ;; 98 99 ... 100 ---------------------------- 101 END OF INNODB MONITOR OUTPUT 102 ============================ 103 ^C 104 105 //Only an "IX" intention lock and an "X" record lock were found.There's no "IS" intention lock any more. 106 //Intention locks between transactons does not block each other,they don't conflict.Therefore,when session 2 is gonna to get "X" lock(for update),the "IX" intention lock was generated and the "IS" intention in session 1 didn't appear. 107 //How about reversing the operations in session 1 and session 2?Let's see below. 108 109 //Session 1: 110 zlm@192.168.56.100:3306 [zlm]>begin;select * from t for update; 111 Query OK, 0 rows affected (0.00 sec) 112 113 +----+------+ 114 | id | name | 115 +----+------+ 116 | 1 | aaa | 117 | 2 | bbb | 118 | 4 | ccc | 119 | 6 | fff | 120 +----+------+ 121 4 rows in set (0.00 sec) 122 123 //Session 2: 124 zlm@192.168.56.100:3306 [(none)]>begin;select * from t where name = 'aaa' lock in share mode; 125 Query OK, 0 rows affected (0.00 sec) 126 127 ERROR 1046 (3D000): No database selected 128 zlm@192.168.56.100:3306 [(none)]>begin;select * from zlm.t where name = 'aaa' lock in share mode; 129 Query OK, 0 rows affected (0.00 sec) 130 131 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 132 zlm@192.168.56.100:3306 [(none)]> 133 134 //Check the error log. 135 [root@zlm1 04:31:00 /data/mysql/mysql3306/data] 136 #tail -f error.log 137 138 ... 139 ------------ 140 TRANSACTIONS 141 ------------ 142 Trx id counter 2996012 143 Purge done for trx's n:o < 2996003 undo n:o < 0 state: running but idle 144 History list length 12 145 LIST OF TRANSACTIONS FOR EACH SESSION: 146 ---TRANSACTION 2996011, ACTIVE 26 sec 147 2 lock struct(s), heap size 1136, 5 row lock(s) 148 MySQL