kill命令
# kill命令
kill query id:表示中止当前线程id正在执行的语句。
kill (connection) id:表示杀掉并断开该线程的连接。
当前查询语句执行慢,或是存在锁等待,都可以直接kill。
# 被kill掉的线程发生了什么?
A线程执行kill query thread_B命令关闭B线程的查询操作后,MySQL里处理kill命令的线程做了两件事:
- 将B线程的线程状态设置为THD::KILL_QUERY
- 给B线程发送一个信号
B线程执行查询语句的过程中,在“埋点”处判断线程状态,如果发现状态处于THD::KILL_QUERY,才开始进入语句终止逻辑。
# 居然kill不掉?
# 情况一、线程没有执行到状态判断逻辑
假定当前并发查询线程数为2,线程C执行查询语句时当前并发线程数已达阈值,因此被阻塞。
然而线程D关闭当前C线程的查询操作时,线程C并没有反应。等到线程E直接断开线程C的连接时才有反应。

线程C在被阻塞的情况下,它的等待逻辑是每隔10毫秒轮询判断是否可以进入InnoDB执行,如果不行则进入sleep状态。虽然线程D已经修改了C的状态同时发送了i信号,但是在整个轮询进入InnoDB的过程中,C并没有进入埋点判断状态,也就不会执行终止逻辑。
而对于线程E来说,关闭连接主要做了两件事:
- 讲C线程的状态设置为THD::KILL_CONNECTION
- 关闭C线程的网络连接
关闭网络连接之后线程C马上收到了提示。show processlist可以发现kill掉的线程依然存在(killed),只有等到线程C进入InnoDB执行查询条件前,判断当前状态已经被kill掉后才会真正进入终止逻辑。
# 情况二、终止逻辑耗时较长
终止逻辑执行时间较长,只有等到完整的执行完后,才算是真正结束。常见有以下场景:
- 大事务执行期间被kill掉。此时整个终止逻辑中,还包括对整个大事务的回滚操作,非常耗时。
- 大查询回滚。整个终止逻辑中,需要删除查询过程中产生的临时文件,文件大可能就需要等待IO资源,导致耗时增加。
- DDL命令执行到最后阶段,忽然被kill掉,终止逻辑中处理临时文件的耗时也会比较大。
总结:对于情况一可以手动提高并发线程数,让被kill掉的线程更快执行终止逻辑。而情二可以减少系统IO压力让它加速。
# MySQL客户端连接问题
# 问题一、连接状态与表的数量
问题1
客户端连接时,如果库中的表数量比较多的情况下,会发现连接数据库时比较慢。
客户端进行数据库连接时,会做以下几个步骤:
- 客户端与MySQL服务端进行TCP握手,用户校验,获取权限。
- 连接成功后,MySQL客户端会提供一个TAB快捷键自动补全库名和表名的功能。而要实现这个功能,客户端还要进行以下操作:
- 执行show databases;获取库名
- 执行show tables;获取表名
- 把上述两个结果用于在本地构建一个哈希表
显然客户端连接时,感知到的慢正是因为构建哈希表才比较慢。客户端在连接时,可以添加-A来关闭这个自动补全功能。
# 问题二、-quick参数
问题2
客户端连接时,指定-quick参数并不会加速服务端,反而会影响服务端性能。
MySQL客户端发送请求后,接收服务端返回结果的方式有两种:
本地开一片内存,将服务端结果保存起来。
不缓存,本地(客户端)处理完一个返回结果后,再接收读取另一个结果。
MySQL默认采用第一种缓存的方式。在客户端连接命令加上-quick后,那么就会使用上面第二种不缓存的方法。如果采用不缓存的方法影响如下:
- 对于服务端来说,如果客户端本地没有处理完,那么当前服务端的发送结果就会被阻塞,从而导致服务端变慢
- 对于客户端而言,①可以减少本地内存占用 ②跳过表名自动补全 ③❓不会把执行命令记录到本地的命令历史文件
总结:-quick参数有利于客户端,而不利于服务端。