鎖介紹的那篇中已經提到了這個命令,如今咱們開一個參數,更細緻的分析一下這個命令mysql
(root@localhost) [(none)]> set global innodb_status_output_locks=1; Query OK, 0 rows affected (0.00 sec)
(root@localhost) [test]> begin; Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> delete from l where a = 2; Query OK, 1 row affected (0.00 sec) (root@localhost) [test]> update l set b = b + 1 where a = 4; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 (root@localhost) [test]> show engine innodb status\G ... LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 30217412, ACTIVE 37 sec 2 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 2 MySQL thread id 355, OS thread handle 140483080300288, query id 1263 localhost root starting show engine innodb status TABLE LOCK table `test`.`l` trx id 30217412 lock mode IX RECORD LOCKS space id 1358 page no 3 n bits 72 index PRIMARY of table `test`.`l` trx id 30217412 lock_mode X locks rec but not gap Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 32 0: len 4; hex 80000002; asc ;; 1: len 6; hex 000001cd14c4; asc ;; 2: len 7; hex 2400000fc21499; asc $ ;; 3: len 4; hex 80000004; asc ;; 4: len 4; hex 80000006; asc ;; 5: len 4; hex 80000008; asc ;; Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 0 0: len 4; hex 80000004; asc ;; 1: len 6; hex 000001cd14c4; asc ;; 2: len 7; hex 2400000fc214c8; asc $ ;; 3: len 4; hex 80000007; asc ;; 4: len 4; hex 80000008; asc ;; 5: len 4; hex 8000000a; asc ;; ...
解析:sql
Q? 表中是四個列,爲何這把是6個列?session
session1:oracle
(root@localhost) [test]> begin; Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> delete from l where a = 2; Query OK, 1 row affected (0.00 sec)
session2:sqlserver
(root@localhost) [test]> begin; Query OK, 0 rows affected (0.00 sec) (root@localhost) [test]> select * from l where a=2 for update; hang住了
session3:spa
... LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 421958478909040, not started 0 lock struct(s), heap size 1136, 0 row lock(s) ---TRANSACTION 30217455, ACTIVE 1741 sec starting index read mysql tables in use 1, locked 1 LOCK WAIT 2 lock struct(s), heap size 1136, 2 row lock(s) MySQL thread id 396, OS thread handle 140483215816448, query id 2340 localhost root statistics select * from l where a=2 for update ------- TRX HAS BEEN WAITING 27 SEC FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 1358 page no 3 n bits 72 index PRIMARY of table `test`.`l` trx id 30217455 lock_mode X locks rec but not gap waiting Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 32 0: len 4; hex 80000002; asc ;; 1: len 6; hex 000001cd14ee; asc ;; 2: len 7; hex 230000013d27d5; asc # =' ;; 3: len 4; hex 80000004; asc ;; 4: len 4; hex 80000006; asc ;; 5: len 4; hex 80000008; asc ;; ------------------ TABLE LOCK table `test`.`l` trx id 30217455 lock mode IX RECORD LOCKS space id 1358 page no 3 n bits 72 index PRIMARY of table `test`.`l` trx id 30217455 lock_mode X locks rec but not gap waiting Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 32 0: len 4; hex 80000002; asc ;; 1: len 6; hex 000001cd14ee; asc ;; 2: len 7; hex 230000013d27d5; asc # =' ;; 3: len 4; hex 80000004; asc ;; 4: len 4; hex 80000006; asc ;; 5: len 4; hex 80000008; asc ;; ---TRANSACTION 30217454, ACTIVE 1821 sec 2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1 MySQL thread id 355, OS thread handle 140483080300288, query id 2339 localhost root TABLE LOCK table `test`.`l` trx id 30217454 lock mode IX RECORD LOCKS space id 1358 page no 3 n bits 72 index PRIMARY of table `test`.`l` trx id 30217454 lock_mode X locks rec but not gap Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 32 0: len 4; hex 80000002; asc ;; 1: len 6; hex 000001cd14ee; asc ;; 2: len 7; hex 230000013d27d5; asc # =' ;; 3: len 4; hex 80000004; asc ;; 4: len 4; hex 80000006; asc ;; 5: len 4; hex 80000008; asc ;; ...
(root@localhost) [test]> show processlist; +-----+------+-----------+------+---------+------+----------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +-----+------+-----------+------+---------+------+----------+------------------+ | 355 | root | localhost | test | Query | 0 | starting | show processlist | | 396 | root | localhost | test | Sleep | 1321 | | NULL | +-----+------+-----------+------+---------+------+----------+------------------+ 2 rows in set (0.00 sec) 注意再thread_id表中就不同了,是對應proceelist_id (root@localhost) [test]> select thread_id,processlist_id,thread_os_id from performance_schema.threads where processlist_id is not NULL; +-----------+----------------+--------------+ | thread_id | processlist_id | thread_os_id | +-----------+----------------+--------------+ | 27 | 1 | 10574 | | 381 | 355 | 18745 | | 422 | 396 | 10592 | +-----------+----------------+--------------+ 3 rows in set (0.00 sec) 分別表示內部線程號(自增的),對應show processlist裏的id,進程號
重複以前的步驟,一邊開一個事務刪除2這條記錄不提交,另外一邊用for update查2這條記錄 (root@localhost) [(none)]> SELECT -> r.trx_id waiting_trx_id, -> r.trx_mysql_thread_id waiting_thread, -> r.trx_query wating_query, -> b.trx_id blocking_trx_id, -> b.trx_mysql_thread_id blocking_thread, -> b.trx_query blocking_query -> FROM -> information_schema.innodb_lock_waits w -> INNER JOIN -> information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id -> INNER JOIN -> information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id; +----------------+----------------+--------------------------------------+-----------------+-----------------+----------------+ | waiting_trx_id | waiting_thread | wating_query | blocking_trx_id | blocking_thread | blocking_query | +----------------+----------------+--------------------------------------+-----------------+-----------------+----------------+ | 30217455 | 396 | select * from l where a=2 for update | 30217454 | 355 | NULL | +----------------+----------------+--------------------------------------+-----------------+-----------------+----------------+ 1 row in set, 1 warning (0.02 sec)
5.7纔有sys庫,不過5.6也能夠自行把sys庫弄進去線程
(root@localhost) [(none)]> select * from sys.innodb_lock_waits\G *************************** 1. row *************************** wait_started: 2018-06-03 00:52:01 wait_age: 00:00:14 wait_age_secs: 14 locked_table: `test`.`l` locked_index: PRIMARY locked_type: RECORD waiting_trx_id: 30217455 waiting_trx_started: 2018-06-03 00:11:13 waiting_trx_age: 00:41:02 waiting_trx_rows_locked: 5 waiting_trx_rows_modified: 0 waiting_pid: 396 waiting_query: select * from l where a=2 for update waiting_lock_id: 30217455:1358:3:2 waiting_lock_mode: X blocking_trx_id: 30217454 blocking_pid: 355 blocking_query: NULL blocking_lock_id: 30217454:1358:3:2 blocking_lock_mode: X blocking_trx_started: 2018-06-03 00:09:53 blocking_trx_age: 00:42:22 blocking_trx_rows_locked: 1 blocking_trx_rows_modified: 1 sql_kill_blocking_query: KILL QUERY 355 sql_kill_blocking_connection: KILL 355 1 row in set, 3 warnings (0.09 sec)
tips:3d
剛纔模擬鎖等待過程當中出現了下面得報錯指針
(root@localhost) [test]> select * from l where a=2 for update; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
這叫鎖等待超時,開發人員一般把這個和死鎖混爲一談rest
lock持有的時間是以事務爲單位的,事務提交後纔會把事務裏全部的鎖釋放,這是沒法避免的,不過能夠經過一個參數來控制超時時間
(root@localhost) [test]> show variables like 'innodb_lock_wait_timeout'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | innodb_lock_wait_timeout | 50 | +--------------------------+-------+ 1 row in set (0.00 sec)
默認50s,建議設置爲3s左右便可
innodb中頁裏面的記錄是邏輯有序的
一個頁中,第一條插入的記錄heap no是2,後面插入的heap no遞增,這樣在堆中就是有序的了,可是記錄之間又是邏輯有序的,經過指針鏈接
heap no表示插入時的順序,用來表示一個page中的record是何時插入的,因此加鎖的定位是space->page_no->heap_no
一個page中,一條記錄都沒有,innodb默認會生成兩條虛擬僞記錄,min和max,min的heap_no是0,max的heap_no是1,因此用戶插入的記錄heap_no都是從2開始
max上是能夠加鎖的,min上面一般不加鎖
補充sqlserver和innodb全表更新對比
sqlserver每一個記錄一個鎖對象
若是佔用10字節,300w個page,每一個page100條記錄
InnoDB:300M(300w*100/1000/1000)
sqlserver:3G(300w10010/1000/1000)
tips: