读mysql45讲-kill查询线程

在mysql中有两个kill命令:

  • kill query +线程id;表示终止这个正在执行的线程
  • kill connection +线程id,connection可以省略不写,表示断开这个线程的连接,如果这个线程正在执行,那就尝试先停止执行的任务,然后再尝试停止连接。

本质上kill connection id只是断开连接,实际停止线程还是再走一遍kill query id的流程的。

kill线程成功

上面的图中就是正常kill query id成功的情况,在session中执行kill query threae_id_B命令的时候,sessionB几乎是同时就报错了。
执行kill命令后,sessionB并不是直接就终止掉线程,因为当对一个表进行增删改查的操作的时候,会给这个表加一个MDL读锁,所以sessionB虽然是阻塞的,但是会持有一个MDL读锁,如果这个时候就终止线程的话,就没有机会释放这个读锁了。实际上在kill命令执行后是告诉sessionB不用再执行了,可以开始走终止线程的逻辑了,大概的流程如下:

  • 把sessionB线程的运行状态改为THD:KILL_QUERY
  • 给sessionB线程发出一个终止线程的信号

发出一个停止的信号是此时sessionB的线程是处于阻塞状态,如果只是把运行状态改了,那sessionB的线程是无法得知的,还是会继续等待;所以发出一个终止信号,sessionB的线程在接收到这个信号之后开始走终止线程的流程。

在上面的分析中可以知道:

  • 一个语句的执行过程中有多个埋点,只有在走到埋点的地方的时候,线程才会去接收终止信号,判断运行状态,然后开始终止线程。
  • 如果线程是处于等待状态,那么一定需要是可以被终止信号有关唤醒的,不然就只会处于等待状态,然后被正常唤醒。

kill无效

在sessionD中执行kill query 是没有反应的,但是在sessionE是可以看到sessionC报了个错;这个时候如果使用show processlist命令查看,是可以看到sessionC的线程的Command那一列的状态是killed,也就是说虽然连接是断开了,但是其实还在执行中。

这个和第一个示例不一样的区别就是:
第一个线程在等待行锁的时候进入等待状态调用的是是pthread_cond_timedwait函数,这个函数是可以被唤醒的。但是这个第二个示例中等待线程的逻辑是:每过10秒判断一下是否可以进入InnoDB执行,如果不行调用nanosleep函数进入等待状态,也就是虽然这个线程已经被断开连接了,也就是状态已经改为了killed,但是在判断能否进入的逻辑中并没有去判断运行状态,所以不会去进入终止线程的代码中。

如果一个线程的状态是KILL_CONNECTION,就把Command列显示成Killed。

线程在没有执行到判断线程状态的逻辑中之前,是不会终止线程的。

还有一种情况终止过程比较耗时,这个时候用show processlist查看状态是killed,需要等待终止过程结束才会消失。

终止逻辑耗时的背景可能是:

  1. 超大事务执行期间被kill。这时候,回滚操作需要对事务执行期间生成的所有新数据版本做回 收操作,耗时很长。
  2. 大查询回滚。如果查询过程中生成了比较大的临时文件,加上此时文件系统压力大,删除临时文件需要等待IO资源,导致耗时较长。
  3. DDL命令执行到最后阶段,如果被kill,需要删除中间过程的临时文件,也可能受IO资源影响 耗时较久。
有第一个误解是,如果库里面的表很多,连接就会慢

实际上,当使用默认连接的时候,MYSQL会提供一个本地库名和补全表明的功能,为了实现这个功能,客户端在连接时候需要多一些操作:

  • 执行 show database
  • 切到db1,然后show tables
  • 把这两个命令中查询到的所有库和表构建一个本地的哈希表

主要的时间就耗费在第三种构建哈希表中,构建这个哈希表是在本地完成的,所以其实主要慢在本地,而不是连接过程慢。
可以在连接命令中加上-A参数,就可以关闭自动补全的功能,这里自动补全的效果就是,你在输入库名或者表名的时候,输入前缀,可以使用Tab键自动补全表名或者显示提示。

除了-A参数,加上-quick参数也可以跳过这个阶段,但是加上这个参数,可能会降低服务端的性能,MYSQL客户端发送请求之后,接收服务端返回结果的方式有两种:

  1. 在本地开启一段内存,当作缓存,将返回结果存储起来,如果使用API,就是对应的mysql_store_result方法
  2. 不缓存,读一个处理一个,使用API开发对应的就是mysql_use_result方法。

使用了-quick方法之后就是使用第二个方式,如果本地处理的慢,那么就会导致服务端发送结果也会被影响到。
使用-quick参数的好处:

  • 跳过了构建库名和表名的哈希表的操作
  • 不用申请内存去存储返回结果
  • 因为不走缓存,所以不需要存储每次查询的命令(我理解的就是不用记录每次的查询sql)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值