如何快速杀掉堵塞MySQL的会话

Posted 进击的CJR

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何快速杀掉堵塞MySQL的会话相关的知识,希望对你有一定的参考价值。


事务表和锁相关表


查找Innodb里面的锁,可以通过information_schema库下相关事务表和锁相关信息表来查到,在8.0的环境下,通过sys库下的锁相关表查询。


information_schema.innodb_trx
存储了当前正在执行的事务信息

information_schema.innodb_locks
记录了锁信息如果一个事务想要获取到某个锁但未获取到,则记录该锁信息如果一个事务获取到了某个锁,但是这个锁阻塞了别的事务,则记录该锁信息但是无法通过该表查询到谁被阻塞,谁持有未释放。

information_schema.innodb_lock_waits
表明每个阻塞的事务是因为获取不到哪个事务持有的锁而被阻塞

information_schema.processlist
连接信息表

performance_schema.events_statements_current
记录当前执行的sql

performance_schema.events_statements_history
记录执行过的sql


sys.innodb_lock_waits 表

locked_table : 哪张表出现的等待

waiting_trx_id: 等待的事务(与上个视图trx_id 对应)

waiting_pid : 等待的连接号(与上个视图trx_mysql_thread_id或processlist_id)

blocking_trx_id : 锁源的事务ID

blocking_pid : 锁源的连接号


单一的锁快速查找方法


通过information_schema库下的锁信息表查询


整个流程如下:

(1)首先查询是否有锁,根据锁查到被锁的trx_id

(2)根据被锁的trx_id可以查到锁源的trx_id

(3)根据锁源的trx_id查到trx_mysql_thread_id(即processlist_id)

(4)再根据trx_mysql_thread_id查到thread_id

(5)最后,用thread_id查找到锁源的sql

但是这种方法在mysql8.0已经被移除,介绍另外一张表


通过sys库下的锁信息表查询

注意:MySQL8.0删除了information_schema.innodb_locks,添加了performance_schema.data_locks,可以通过performance_schema.data_locks查看事务的锁情况,和MySQL5.7及之前不同,performance_schema.data_locks不但可以看到阻塞该事务的锁,还可以看到该事务所持有的锁,也就是说即使事务并未被阻塞,依然可以看到事务所持有的锁(不过,正如文中最后一段所说,performance_schema.data_locks并不总是能看到全部的锁)。表名的变化其实还反映了8.0的performance_schema.data_locks更为通用了,即使你使用InnoDB之外的存储引擎,你依然可以从performance_schema.data_locks看到事务的锁情况。

因此第一种方法并不适用于8.0


通过sys库查询流程如下和第一种方式的原理其实是一样的

锁源的事务trx_id -->pnformaction_schema.processlist表的连接id-->performance_schema.threads表的thread_id-->performance_schema.events_statements_current 或performance_schema.events_statements_history查看sql


需要注意的是如下的三个id其实是同一个id,我这里把他们同称为连接ID,因为是由CONNECTION_ID()函数返回的

information_schema.innodb_trx(trx_mysql_thread_id)

information_schema.processlist(id)

sys.innodb_lock_waits(waiting_pid,blocking_pid)           


复杂的锁环境怎么快速查找肇事者


innodb_lock_waits

表明每个阻塞的事务是因为获取不到哪个事务持有的锁而被阻塞

requesting_trx_id:--获取不到锁而被阻塞的事务id(等待方)

requested_lock_id:-- 请求锁ID ,事务所等待的锁定的 ID。可以和 INNODB_LOCKS 表 JOIN。

blocking_trx_id: --获取到别的事务需要的锁而阻塞其事务的事务id(当前持有方,待释放)

blocking_lock_id: --这一事务的锁的 ID,该事务阻塞了另一事务的运行。可以和 INNODB_LOCKS 表 JOIN。


sys.innodb_lock_waits 表

locked_table : 哪张表出现的等待

waiting_trx_id: 等待的事务(与上个视图trx_id 对应)

waiting_pid : 等待的连接号(与上个视图trx_mysql_thread_id或processlist_id)

blocking_trx_id : 锁源的事务ID

blocking_pid : 锁源的连接号


sys.innodb_lock_waits的来源

SELECT r.trx_wait_started AS wait_started,
TIMEDIFF(NOW(), r.trx_wait_started) AS wait_age,
TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) AS wait_age_secs,
rl.lock_table AS locked_table,
rl.lock_index AS locked_index,
rl.lock_type AS locked_type,
r.trx_id AS waiting_trx_id,
r.trx_started as waiting_trx_started,
TIMEDIFF(NOW(), r.trx_started) AS waiting_trx_age,
r.trx_rows_locked AS waiting_trx_rows_locked,
r.trx_rows_modified AS waiting_trx_rows_modified,
r.trx_mysql_thread_id AS waiting_pid,
sys.format_statement(r.trx_query) AS waiting_query,
rl.lock_id AS waiting_lock_id,
rl.lock_mode AS waiting_lock_mode,
b.trx_id AS blocking_trx_id,
b.trx_mysql_thread_id AS blocking_pid,
sys.format_statement(b.trx_query) AS blocking_query,
bl.lock_id AS blocking_lock_id,
bl.lock_mode AS blocking_lock_mode,
b.trx_started AS blocking_trx_started,
TIMEDIFF(NOW(), b.trx_started) AS blocking_trx_age,
b.trx_rows_locked AS blocking_trx_rows_locked,
b.trx_rows_modified AS blocking_trx_rows_modified,
CONCAT(KILL QUERY , b.trx_mysql_thread_id) AS sql_kill_blocking_query,
CONCAT(KILL , b.trx_mysql_thread_id) AS sql_kill_blocking_connection
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
INNER JOIN information_schema.innodb_locks bl ON bl.lock_id = w.blocking_lock_id
INNER JOIN information_schema.innodb_locks rl ON rl.lock_id = w.requested_lock_id
ORDER BY

可以发现information_schema.innodb_lock_waits的blocking_trx_id中出现次数最多的事务ID很可能就是堵塞的源头,而sys.innodb_lock_waits中的信息正是完全来自information_schema.innodb_lock_waits和其他两个表的join


(1)执行语句找出堵塞最多的session

select trim(LEADING KILL  from sql_kill_blocking_connection),count(*)
from sys.innodb_lock_waits
group by trim(LEADING KILL from sql_kill_blocking_connection) order by count(*) desc;


(2)

排名第一个的说明堵塞的会话越多。

找到排名第一的process id 当前的事务信息

观察其事务状态和可能执行的语句或者上一条语句判断是否可以杀掉。

select trx_id,trx_operation_state,trx_mysql_thread_id prs_id,now(),trx_started,
to_seconds(now())-to_seconds(trx_started) trx_es_time,
user,db,host,state,Time,info current_sql,PROCESSLIST_INFO last_sql
from information_schema.innodb_trx t1,information_schema.processlist t2,performance_schema.threads t3
where t1.trx_mysql_thread_id=t2.id
and t1.trx_mysql_thread_id=t3.PROCESSLIST_ID
and t1.trx_mysql_thread_id!=connection_id()
and t2.id=;






















以上是关于如何快速杀掉堵塞MySQL的会话的主要内容,如果未能解决你的问题,请参考以下文章

堵塞MySQL的会话是如何被快速杀掉的

InnoDB快速定位行锁争用会话的过程和操作

ORACLE快速彻底Kill掉的会话

如何彻底杀掉Oracle相关用户的会话

如何迅速杀掉数据库里inactive的会话

技巧如何让普通用户可以杀掉自己用户的会话