MySQL行锁-事务锁排查方法
[ 参考文档 ] : 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;