[ 参考文档 ] : https://bbs.huaweicloud.com/blogs/363270

基本流程-找到被阻塞的SQL

​ 一般到这里就可以了,找到SQL开发进行代码排查

-- 查当前行锁数量(确认有锁)
-- 重点字段:
-- Innodb_row_lock_current_waits 当前等待锁的数量(重点关注)
-- Innodb_row_lock_time_max 从系统启动算起,等待锁最长的一次时间
SHOW status like 'innodb_row_lock%';

-- 查等正在等待锁的事务(被阻塞)
-- 重点字段:
-- trx_id 事务ID
-- trx_state 事务状态 RUNNING进行中 / LOCK WAIT等待中 / ROLLING BACK回滚中 / COMMITTING提交中 (关注LOCK WAIT)
-- trx_query 被阻塞的语句(通过这个来知道是哪个sql被阻塞)
SELECT * FROM information_schema.INNODB_TRX WHERE trx_state='LOCK WAIT';

进阶流程-找到持有锁的SQL

​ 可以进一步找到占有的SQL,一般可以在基本流程中通过代码排查找到

-- 查持正在持有锁的进程(正在占用)
-- 重点字段:
-- blocking_pid 锁源的进程ID(相当于process_id,与show full processlist的id对应)
-- blocking_trx_id 锁源的事务ID
-- waiting_trx_id 等待中的事务id号(与查询等待中的trx_id对应)
-- locked_table 锁源占用的表
-- locked_index 上锁的索引
-- locked_type 锁的类型 行级锁(Record Lock)、间隙锁(Gap Lock)、自增锁(Next-Key Lock)
-- waiting_query 被阻塞的SQL(与查询等待中的trx_query对应)
SELECT * FROM sys.innodb_lock_waits;

-- 根据 process_id 找到 锁源的sql线程id(即 thread_id)
-- 重点字段:
-- THREAD_ID 锁源的thread_id
SELECT * FROM performance_schema.threads WHERE processlist_id = #{blocking_pid};

-- 根据 thread_id 找到 持有锁的SQL
-- 重点字段:
-- thread_id 线程ID
-- sql_text 锁源的sql语句
SELECT * FROM performance_schema.events_statements_current WHERE thread_id = #{thread_id};

-- 也可以根据 thread_id 找到 该进程历史执行的SQL
-- 重点字段:
-- thread_id 线程ID
-- sql_text 该 thread 历史执行SQL
SELECT * FROM performance_schema.events_statements_history WHERE thread_id = #{thread_id};

​ SQL组合,一部到位

SELECT 
	-- 锁源的进程ID
	w.blocking_pid,
	-- 锁源的事务ID
	w.blocking_trx_id,
	-- 阻塞的事务ID
	w.waiting_trx_id,
	-- 锁的表
	w.locked_table,
	-- 锁类型
	w.locked_type,
	-- 被阻塞的SQL
	w.waiting_query,
	-- 锁源的SQL
	c.SQL_TEXT 
FROM
	-- 锁等待表
	`sys`.innodb_lock_waits w,
	-- 线程表
	`performance_schema`.threads t,
	-- 线程当前事件表
	`performance_schema`.events_statements_current c
WHERE
	w.blocking_pid = t.processlist_id
AND
	t.THREAD_ID = c.THREAD_ID;