MySQL中存在着两个kill命令,一个是kill query+线程id 表示停止执行语句,一个是kill connection + 线程id 表示断开线程的连接
但是有时候使用kill命令,没能断开这个线程,再次执行show proccesslist的命令的时候,发现Command列显示的是killed
为何没有断开这个线程,
我们要想一想,收到了kill命令后,线程会做什么
加入sessionB直接终止了线程,什么都不管就直接退出,显然是不行的
但是当对一个表有增删改查操作的时候,会在表上加MDL读锁,如果sessionB处于blocked状态,直接杀死的话,这个MDL读锁就没法释放了
这样的话,kill就只是告诉线程这个语句可以停止了,不是直接强制停止,跟关闭线程池一样
这就是和linux的kill命令类似,只是发一个信息,告诉线程进入终止逻辑,但是并不强制关闭
然后kill query thread_id_x时候,MySQL做了两件事
将session B的状态改为了THD::KILL_QUERY,就是讲killed 赋值为 THD::KILL_QUERY
然后给session B发一个信号
一个语句执行过程中,有多处埋点,在这些埋点的地方判断线程状态,如果发现有THD::KILL_QUERY,就进行语句的终止
如果一个语句处于无法被唤醒的状态,那么不会执行到埋点的地方
这个语句从发起终止到完成终止,不是说停就停的
比如我们看一下kill不掉的例子
就是工作并发线程已经满了
首先设置innodb_thread_concrrency=2
接下来两个sleep命令将所有工作线程占用了
接下来sessionC执行的时候,就被堵住了
sessionD执行的kill query C就没什么用了
执行kill connection,才能断开session C的连接
但是看show processlist,可以看到如下的图
这就出现了killed不掉的情况了
当session 执行kill connection 的时候,是这么做的
将线程设置为KILL_CONNECTION
然后关闭线程的网络连接,导致客户端可以收到断开的提示
而且无法kill的原因总结为:
1.kill无效,就如同上面的线程无法执行,或者是IO压力大,导致分配不到资源
2.终止逻辑耗时过长
对于2:在大事务执行中进行kill,需要对新数据进行回滚
大查询回滚,查询过程中生成了大的临时文件,需要删除
DDL执行到了后期,需要删除临时文件,耗时长
所以杀死一个线程并不是那么简单的
即使用Ctrl+C来关闭连接,那么kill掉一个线程还需要涉及到其他操作,Ctrl+C只是另起一个连接,发送kill query命令