很多時候我們在MySQL資料庫中會經常出現事務之間阻塞的問題,也就是阻塞lock,oracle的話實際上之前提供的腳本已經可以很直觀看出阻塞的問題,那麼對於mysql資料庫我們應如何快速查找定位問題根源?
這裡用實驗來進行演示。
資料庫:mysql5.7.24 作業系統:centos7.3
1、數據準備
create database t DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
use t;
create table test_blocking(id int primary key, name varchar(12));
insert into test_blocking select 1, 'hwb' from dual;
insert into test_blocking select 2, 'hwb2' from dual;
insert into test_blocking select 3, 'hwb3' from dual;
2、參數設置
為了實驗效果,我們先將參數innodb_lock_wait_timeout設置為100,否則很快就會提示ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
show variables like 'innodb_lock_wait_timeout';
set global innodb_lock_wait_timeout=100 ;
1、第一個會話
select connection_id() from dual;
set session autocommit=0;
select * from test_blocking where id=1 for update;
2、第二個會話
在第二個連接會話中執行更新腳本
select connection_id() from dual;
update test_blocking set name='kk' where id=1;
3、第三個會話-- show engine innodb status分析
在第三個連接會話執行下面命令,查看TRANSACTIONS相關信息
show engine innodb status\\G;
使用show engine innodb status命令後,可以查看其輸出的TRANSACTIONS部分信息,如上截圖所示,找到類似TRX HAS BEEN WATING ...部分的信息,
通過那部分信息,我們可以看到update test_blocking set name='kk' where id=1這個SQL語句被阻塞了88秒,一直在等待獲取X Lock。
------------
TRANSACTIONS
------------
Trx id counter 7554368 #下一個事務ID
Purge done for trx's n:o < 7554368 undo n:o < 0 state: running but idle
History list length 8
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421427521662128, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421427521657568, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421427521656656, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421427521659392, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421427521658480, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 7554359, ACTIVE 88 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 304193, OS thread handle 139951793415936, query id 20504960 localhost root updating
#MYSQL線程ID為304193, 作業系統線程句柄為139951793415936, 查詢ID為20504960,帳號為本地的root的UPDATE操作
update test_blocking set name='kk' where id=1 #具體SQL語句
------- TRX HAS BEEN WAITING 88 SEC FOR THIS LOCK TO BE GRANTED: #TRX等待授予鎖已經有88秒了
RECORD LOCKS space id 6143 page no 3 n bits 72 index PRIMARY of table `t`.`test_blocking` trx id 7554359 lock_mode X locks rec but not gap waiting
#在space id=6143(test_blocking表的表空間),page no=3的頁上,表test_blocking上的主鍵索引在等待X鎖
Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 4; hex 80000001; asc ;; #第一個欄位是主鍵,制度按長為4,值為1
1: len 6; hex 000000734138; asc sA8;; #該欄位為6個位元組的事務id,這個id表示最近一次被更新的事務id(需做十進位轉換)
2: len 7; hex a4000140130110; asc @ ;; #該欄位為7個位元組的回滾指針,用於mvcc
3: len 3; hex 687762; asc hwb;; #該欄位表示的是此記錄的第二個欄位,長度為5,值為hwb(如果表有多個欄位,那麼此處後面還有記錄)
------------------
---TRANSACTION 7554352, ACTIVE 144 sec
2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 304192, OS thread handle 139952113923840, query id 20504801 localhost root
--------
一般情況下生產環境很複雜,尤其是有大量事務的情況下。諸多信息根本無法清晰判斷知道誰阻塞了誰;其次一點也不直觀; 另外,這個也無法定位blocker 的SQL語句。這種方式只能作為輔助分析用途,通過查看取鎖的詳細信息,幫助進一步診斷問題。
後面會介紹其他幾個方式來定位問題,感興趣的朋友可以關注下~