前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >32 | kill不掉的语句

32 | kill不掉的语句

作者头像
HaC
发布于 2020-12-30 09:50:54
发布于 2020-12-30 09:50:54
1.5K00
代码可运行
举报
文章被收录于专栏:HaC的技术专栏HaC的技术专栏
运行总次数:0
代码可运行

MySQL 中有两个 kill 命令:

  1. kill query + 线程 id 表示终止这个线程中正在执行的语句。
  2. kill connection + 线程 id 这里 connection 可缺省,表示断开这个线程的连接,当然如果这个线程有语句正在执行,也是要先停止正在执行的语句的。

其实大多数情况下,kill query/connection 命令是有效的。比如,执行一个查询的过程中,发现执行时间太久,要放弃继续查询,这时我们就可以用 kill query 命令,终止这条查询语句。

比如 :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
BEGIN ;
SELECT * FROM t WHERE c =10 for UPDATE;

查看:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
show processlist;
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
KILL 21;

结果:

还有一种情况是,语句处于锁等待的时候,直接使用 kill 命令也是有效的。 例子:

session C 执行 kill query 以后,session B 几乎同时就提示了语句被中断。这,就是我们预期的结果。

对一个表做增删改查操作时,会在表上加 MDL 读锁。所以,session B 虽然处于 blocked 状态,但还是拿着一个 MDL 读锁的。如果线程被 kill 的时候,就直接终止,那之后这个 MDL 读锁就没机会被释放了。

kill 并不是马上停止的意思,而是告诉执行线程说,这条语句已经不需要继续执行了,可以开始“执行停止的逻辑了”。

其实,这跟 Linux 的 kill 命令类似,kill -N pid 并不是让进程直接停止,而是给进程发一个信号,然后进程处理这个信号,进入终止逻辑。只是对于 MySQL 的 kill 命令来说,不需要传信号量参数,就只有“停止”这个命令。

当用户执行 kill query thread_id_B 时,MySQL 里处理 kill 命令的线程做了两件事:

  1. 把 session B 的运行状态改成 THD::KILL_QUERY(将变量 killed 赋值为 THD::KILL_QUERY);
  2. 给 session B 的执行线程发一个信号。

session B 处于锁等待状态,如果只是把 session B 的线程状态设置 THD::KILL_QUERY,线程 B 并不知道这个状态变化,还是会继续等待。发一个信号的目的,就是让 session B 退出等待,来处理这个 THD::KILL_QUERY 状态。

上面的分析中,隐含了这么三层意思:

  1. 一个语句执行过程中有多处“埋点”,在这些“埋点”的地方判断线程状态,如果发现线程状态是 THD::KILL_QUERY,才开始进入语句终止逻辑;
  2. 如果处于等待状态,必须是一个可以被唤醒的等待,否则根本不会执行到“埋点”处;
  3. 语句从开始进入终止逻辑,到终止逻辑完全完成,是有一个过程的。

kill不掉的例子:

执行 set global innodb_thread_concurrency=2,将 InnoDB 的并发线程上限数设置为 2;然后,执行下面的序列:

注意:执行kill的时候没进InnoDB,不受这个参数限制的。

可以看到:

  1. sesssion C 执行的时候被堵住了;
  2. 但是 session D 执行的 kill query C 命令却没什么效果,
  3. 直到 session E 执行了 kill connection 命令,才断开了 session C 的连接,提示“Lost connection to MySQL server during query”,但是这时候,
  4. 如果在 session E 中执行 show processlist,你就能看到下面这个图。

这时候,id=12 这个线程的 Commnad 列显示的是 Killed。也就是说,客户端虽然断开了连接,但实际上服务端上这条语句还在执行过程中。

这个kill query 不像 上面的update直接退出。

在实现上,等行锁时,使用的是pthread_cond_timedwait 函数,这个等待状态可以被唤醒。但是,在这个例子里,12 号线程的等待逻辑是这样的:每 10 毫秒判断一下是否可以进入 InnoDB 执行,如果不行,就调用 nanosleep 函数进入 sleep 状态。(只是一直试探是否可以进入,而没有直接退出)。

也就是说,虽然 12 号线程的状态已经被设置成了 KILL_QUERY,但是在这个等待进入 InnoDB 的循环过程中,并没有去判断线程的状态,因此根本不会进入终止逻辑阶段。

而当 session E 执行 kill connection 命令时,是这么做的:

  1. 把 12 号线程状态设置为 KILL_CONNECTION;
  2. 关掉 12 号线程的网络连接。因为有这个操作,所以你会看到,这时候 session C 收到了断开连接的提示。

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

所以其实,即使是客户端退出了,这个线程的状态仍然是在等待中。

那这个线程什么时候会退出呢? 答案是,只有等到满足进入 InnoDB 的条件后,session C 的查询语句继续执行,然后才有可能判断到线程状态已经变成了 KILL_QUERY 或者 KILL_CONNECTION,再进入终止逻辑阶段。

以上这个例子是kill无效的第一种情况,即线程没有执行到判断线程状态的逻辑。跟这种情况还有的例子还有:IO 压力过大,读写 IO 的函数一直无法返回,导致不能及时判断线程的状态。

另一类情况是,终止逻辑耗时较长。这时候,从 show processlist 结果上看也是 Command=Killed,需要等到终止逻辑完成,语句才算真正完成。这类情况,比较常见的场景有以下几种:

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

另外两个关于客户端的误解:

1. 如果库里面的表特别多,连接就会很慢。

如:

每个客户端在和服务端建立连接的时候,需要做的事情就是 TCP 握手、用户校验、获取权限。但这几个操作,显然跟库里面表的个数无关。

当使用默认参数连接的时候,MySQL 客户端会提供一个本地库名和表名补全的功能。为了实现这个功能,客户端在连接成功后,需要多做一些操作:

  1. 执行 show databases;
  2. 切到 db1 库,执行 show tables;
  3. 把这两个命令的结果用于构建一个本地的哈希表。

在这些操作中,最花时间的就是第三步在本地构建哈希表的操作。所以,当一个库中的表个数非常多的时候,这一步就会花比较长的时间。

也就是说,我们感知到的连接过程慢,其实并不是连接慢,也不是服务端慢,而是客户端慢。

图中的提示也说了,如果在连接命令中加上 -A,就可以关掉这个自动补全的功能,然后客户端就可以快速返回了。这里自动补全的效果就是,你在输入库名或者表名的时候,输入前缀,可以使用 Tab 键自动补全表名或者显示提示。

实际使用中,如果你自动补全功能用得并不多,我建议你每次使用的时候都默认加 -A。

2. –quick 是一个更容易引起误会的参数,也是关于客户端常见的一个误解。

MySQL 客户端发送请求后,接收服务端返回结果的方式有两种:

  1. 一种是本地缓存,也就是在本地开一片内存,先把结果存起来。如果你用 API 开发,对应的就是 mysql_store_result 方法。
  2. 另一种是不缓存,读一个处理一个。如果你用 API 开发,对应的就是 mysql_use_result 方法。

MySQL 客户端默认采用第一种方式,而如果加上–quick 参数,就会使用第二种不缓存的方式。采用不缓存的方式时,如果本地处理得慢,就会导致服务端发送结果被阻塞,因此会让服务端变慢。

那你会说,既然这样,为什么要给这个参数取名叫作 quick 呢?这是因为使用这个参数可以达到以下三点效果:

  • 第一点,就是前面提到的,跳过表名自动补全功能。
  • 第二点,mysql_store_result 需要申请本地内存来缓存查询结果,如果查询结果太大,会耗费较多的本地内存,可能会影响客户端本地机器的性能;
  • 第三点,是不会把执行命令记录到本地的命令历史文件。

小结: kill connection本质上只是把客户端的sql连接断开,后面的执行流程还是要走kill query的,额外的一个不同就是show processlist的时候,kill connection会显示“killed”,所以不显示。

一个事务执行很长时间,kill掉,那么,执行这个事务过程中的数据就会回滚。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/02/29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
MySQL实战第三十二讲-为什么还有kill不掉的语句?
在 MySQL 中有两个 kill 命令:一个是 kill query + 线程 id,表示终止这个线程中正在执行的语句;一个是 kill connection + 线程 id,这里 connection 可缺省,表示断开这个线程的连接,当然如果这个线程有语句正在执行,也是要先停止正在执行的语句的。
越陌度阡
2022/05/06
1.3K0
MySQL实战第三十二讲-为什么还有kill不掉的语句?
MySQL 为什么Kill不掉线程
被kill的线程不会立即停止,因为当我们对表做增删改查时,会在表上加MDL读锁,因此如果立即停止,MDL读锁将会无法释放。
shysh95
2022/04/07
2.3K0
MySQL 为什么Kill不掉线程
MySQL中的kill命令,你用过吗?
先来说说这俩语法的概念,第一种kill query pid指的是断开当前线程中正在执行的语句,而不断开线程连接。第二种kill pid的方法指的是断开该线程的连接,如果线程中有正在执行的语句,那么也会停止这个语句。
AsiaYe
2020/05/27
10.7K0
当kill在MySQL中遇到不死金身killed怎么办?|Vol 16
在使用MySQL中,我们对于执行时间过长的SQL想要放弃的方法就是kill这个SQL。在MySQL中kill有两个命令:
wubx
2021/08/06
6.2K0
当kill在MySQL中遇到不死金身killed怎么办?|Vol 16
MySQL 案例:为什么 kill 不掉线程
在日常的使用过程中,时不时会遇到个别,或者大量的连接堆积在 MySQL 中的现象,这时一般会考虑使用 kill 命令强制杀死这些长时间堆积起来的连接,尽快释放连接数和数据库服务器的 CPU 资源。
王文安@DBA
2021/04/21
4.3K0
MySQL 案例:为什么 kill 不掉线程
MySQL 客户端 Ctrl + C,服务端会发生什么?
我们也许有过这样的经历:用 mysql 客户端连上数据库,执行一条 SQL,结果迟迟执行不完,我们等得不耐烦了,顺手就是一个 Ctrl + C。
csch
2023/05/24
7260
MySQL 客户端 Ctrl + C,服务端会发生什么?
MySQL深入学习第十九篇-为什么我只查一行的语句,也执行这么慢?
一般情况下,如果我跟你说查询性能优化,你首先会想到一些复杂的语句,想到查询需要返回大量的数据。但有些情况下,“查一行”,也会执行得特别慢。今天,我就跟你聊聊这个有趣的话题,看看什么情况下,会出现这个现象。
越陌度阡
2020/11/26
1.2K0
MySQL深入学习第十九篇-为什么我只查一行的语句,也执行这么慢?
MySQL kill会话不起作用?
在一次日常测试中发现,kill 一个会话后,SQL语句依然在运行并没终止;被kill的会话重新连接并继续执行原来的SQL语句。
GreatSQL社区
2023/08/10
6480
MySQL kill会话不起作用?
会话和锁信息查询视图 | 全方位认识 sys 系统库
在上一篇《等待事件统计视图 | 全方位认识 sys 系统库》中,我们介绍了sys 系统库中的等待事件统计视图,本期的内容先给大家介绍会话信息和锁等待信息查询视图,通过这些视图我们可以清晰地知道每个会话正在做什么事情,是否存在锁等待。下面请跟随我们一起开始 sys 系统库的系统学习之旅吧~
沃趣科技
2018/09/04
1.6K0
会话和锁信息查询视图 | 全方位认识 sys 系统库
半同步复制after_sync模式下的一则客户端断开问题分析
众所周知,MySQL5.7对于半同步增强的其中一个部分是对ack确认动作的改进。在5.6下的半同步的ack确认是在storage commit之后,这就带来了两个问题
用户1278550
2019/08/16
1.3K1
带你读 MySQL 源码:limit, offset
MySQL 源码数量庞大,各种功能的代码盘根错节,相互交织在一起,形成一张复杂的网。
csch
2023/05/24
1K0
带你读 MySQL 源码:limit, offset
MySQL连接数过多问题(11/16)
十里桃花舞丶
2024/04/12
4170
MySQL 案例:analyze,慢查询,与查询无响应
有时候,遇到同样的 SQL 语句在正式环境的主库和只读实例的执行时间相距甚远时,第一时间就会想到是不是采样信息不一致,导致执行计划不准,从一个高效的查询变成了慢查询。找到问题所在之后,自然是 analyze 一下,重新采集信息就好,这个时候,却发现 analyze 表上的所有 select 突然卡住了,不返回任何结果。
王文安@DBA
2020/09/15
2.9K0
MySQL 案例:analyze,慢查询,与查询无响应
Mysql宕机临时处理方案
在日常开发中,难免会遇到业务高峰期,到时mysql不可用,但是这个时候领导肯定要求的最低限度,就是让业务跑起来,今天我们就说说有哪些方案可以临时解决这种问题
小土豆Yuki
2020/11/19
1.5K0
Mysql宕机临时处理方案
MySQL实战第二十二讲-MySQL有哪些“饮鸩止渴”提高性能的方法?
不知道你在实际运维过程中有没有碰到这样的情景:业务高峰期,生产环境的 MySQL 压力太大,没法正常响应,需要短期内、临时性地提升一些性能。
越陌度阡
2022/05/06
4060
MySQL实战第二十二讲-MySQL有哪些“饮鸩止渴”提高性能的方法?
源码解析丨一次慢SQL排查
* GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。 当long_query_time=1时(表info的id为主键),出现下面的慢日志,可能会让你吃惊 # Time: 2024-01-28T22:52:24.500491+08:00 # User@Host: root[root] @ [127.0.0.1] Id: 8 # Query_time: 7.760787 Lock_time: 7.757456 Rows_sent: 0 Rows_examined: 0 use apple; SET timestamp=; delete from info where id < ;
GreatSQL社区
2024/03/25
940
源码解析丨一次慢SQL排查
【云原生进阶之数据库技术】第一章MySQL-3.1-整体架构
MySQL Server架构自顶向下大致可以分网络连接层、服务层、存储引擎层和系统文件层。
江中散人_Jun
2024/03/05
3560
【云原生进阶之数据库技术】第一章MySQL-3.1-整体架构
史上最详细MySQL全局锁和表锁
墨墨导读:根据加锁的范围,MySQL里面的锁大致可以分成全局锁,表级锁,行锁。本文主要讲述MySQL全局锁和表锁。
数据和云
2019/06/28
3.1K0
史上最详细MySQL全局锁和表锁
如果MySQL事务中发生了网络异常?
在我们运维MySQL的时候,总会遇到各种情况导致程序和MySQL之间的会话异常中断,比如
用户1278550
2020/10/10
3.5K0
如果MySQL事务中发生了网络异常?
MySQL timeout调研与实测
接触网络编程我们不得不提的就是超时,TCP建立连接的超时,数据报文发送/接收超时等等,mysql在超时上也做足了功夫。
九州暮云
2019/08/21
1.1K0
MySQL timeout调研与实测
推荐阅读
相关推荐
MySQL实战第三十二讲-为什么还有kill不掉的语句?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验