前往小程序,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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Django+Vue开发生鲜电商平台之5.使用DRF实现商品列表页和过滤
Github和Gitee代码同步更新: https://github.com/PythonWebProject/Django_Fresh_Ecommerce; https://gitee.com/Python_Web_Project/Django_Fresh_Ecommerce。
cutercorley
2020/07/27
5.5K0
Django+Vue开发生鲜电商平台之5.使用DRF实现商品列表页和过滤
Vue+Django2.0 REST framework 打造前后端分离的生鲜电商项目(五)商品列表页
一、Django2.0的view实现商品列表页 算是对以前django知识的一个回顾,方便跟下面的drf(Django REST framework)实现商品列表页作对比 1.在apps/goods下新建views_base.py文件 1 import json 2 from django.views.generic.base import View 3 4 from .models import Goods 5 6 7 class GoodsListView(View): 8
玩蛇的胖纸
2018/06/08
4.9K0
python测试开发django-rest-framework-88.反序列化
serializers.Serializer可以对modle模型中的字段序列化,并且必须写create和update两个方法。ModelSerializer可以看成是Serializer的一个升级版,功能更强大,更方便。 实际上ModelSerializer类继承了Serializer类
上海-悠悠
2021/02/03
6840
python测试开发django-rest-framework-88.反序列化
Django REST framework+Vue 打造生鲜超市(八) 九、个人中心功能开发
九、个人中心功能开发 9.1.drf的api文档自动生成和 (1) url #drf文档,title自定义 path('docs',include_docs_urls(title='仙剑奇侠传
zhang_derek
2018/04/16
9900
Django REST framework+Vue 打造生鲜超市(八)
		九、个人中心功能开发
Django+Vue开发生鲜电商平台之8.商品详情页功能实现
Github和Gitee代码同步更新: https://github.com/PythonWebProject/Django_Fresh_Ecommerce; https://gitee.com/Python_Web_Project/Django_Fresh_Ecommerce。
cutercorley
2020/07/30
1.2K0
Django+Vue开发生鲜电商平台之8.商品详情页功能实现
Vue+Django2.0 restframework打造前后端分离的生鲜电商项目(3)
1.drf前期准备 1.django-rest-framework官方文档 https://www.django-rest-framework.org/ #直接百度找到的djangorestframe
玩蛇的胖纸
2018/10/10
1.4K0
Vue+Django2.0 restframework打造前后端分离的生鲜电商项目(3)
Django REST framework+Vue 打造生鲜超市(十二) 十三、首页、商品数量、缓存和限速功能开发
十三、首页、商品数量、缓存和限速功能开发  13.1.轮播图接口实现 首先把pycharm环境改成本地的,vue中local_host也改成本地  (1)goods/serializer class BannerSerializer(serializers.ModelSerializer): ''' 轮播图 ''' class Meta: model = Banner fields = "__all__" (2)goods/views.py c
zhang_derek
2018/04/23
2K0
Django REST framework+Vue 打造生鲜超市(十二)
		十三、首页、商品数量、缓存和限速功能开发
(项目)生鲜超市(七)
  商品详情页面只需要在商品列表页的接口中继承mixins.RetrieveModelMixin就可以了:
py3study
2020/01/20
7370
Django_rest框架片段高亮显示实践项目(一)url和view里面的代码的书写
和helloWord项目一样,就是建项目,搭建Djangorest的项目,现在因为是做代码片段高亮显示的项目,所以,需要一个新表,所以我们需要在model.py里面写一个实体类
一写代码就开心
2022/01/21
7640
Django_rest框架片段高亮显示实践项目(一)url和view里面的代码的书写
Django REST framework+Vue 打造生鲜超市(五) 六、商品类别数据展示
六、商品类别数据展示 6.1. 商品类别数据接口 (1)商品分类有两个接口: 一种是全部分类:一级二级三级   一种是某一类的分类以及商品详细信息:  开始写商品分类的接口 (2)序列化 给分类添加三
zhang_derek
2018/04/13
2.4K0
Django REST framework+Vue 打造生鲜超市(五)
		六、商品类别数据展示
Django基础之(十)DRF
coreapi (1.32.0+) - Schema generation support. Markdown (2.1.0+) - Markdown support for the browsable API. django-filter (1.0.1+) - Filtering support. django-crispy-forms - Improved HTML display for filtering. django-guardian (1.1.1+) - Object level permissions support
py3study
2020/01/06
6670
Django rest framework(7)----分页
第一种分页  PageNumberPagination 基本使用 (1)urls.py urlpatterns = [ re_path('(?P<version>[v1|v2]+)/page1
zhang_derek
2018/04/11
1.8K0
Django rest framework(7)----分页
Django+Vue开发生鲜电商平台之11.首页、商品数量、缓存和限速功能开发
Github和Gitee代码同步更新: https://github.com/PythonWebProject/Django_Fresh_Ecommerce; https://gitee.com/Python_Web_Project/Django_Fresh_Ecommerce。
cutercorley
2020/08/05
2.2K0
Django+Vue开发生鲜电商平台之11.首页、商品数量、缓存和限速功能开发
Django REST framework+Vue 打造生鲜超市(七) 八、商品详情页功能
八、商品详情页功能  8.1.viewsets实现商品详情页接口 (1)商品详情页只需要多继承一个类(mixins.RetrieveModelMixin)就可以了 class GoodsListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):  (2)商品轮播图 商品轮播图是一个外键,序列化外键用嵌套的方法来实现 #轮播图 class GoodsImageSerializer(serializ
zhang_derek
2018/04/16
1.2K1
Django REST framework+Vue 打造生鲜超市(七)
		八、商品详情页功能
Django REST framework+Vue 打造生鲜超市(九) 十、购物车、订单管理和支付功能
十、购物车、订单管理和支付功能 10.1.添加商品到购物车 (1)trade/serializer.py # trade/serializer.py __author__ = 'derek' from .models import ShoppingCart from rest_framework import serializers from goods.models import Goods class ShopCartSerializer(serializers.Serializer):
zhang_derek
2018/04/19
1K0
Django REST framework+Vue 打造生鲜超市(九)
		十、购物车、订单管理和支付功能
Django+Vue开发生鲜电商平台之7.用户登录和注册功能
Github和Gitee代码同步更新: https://github.com/PythonWebProject/Django_Fresh_Ecommerce; https://gitee.com/Python_Web_Project/Django_Fresh_Ecommerce。
cutercorley
2020/07/30
4.6K0
Django+Vue开发生鲜电商平台之7.用户登录和注册功能
rest_framework框架的基本组件
快速实例 Quickstart 序列化 创建一个序列化类 简单使用 开发我们的Web API的第一件事是为我们的Web API提供一种将代码片段实例序列化和反序列化为诸如json之类的表示形式的方式。我们可以通过声明与Django forms非常相似的序列化器(serializers)来实现。 models部分: from django.db import models # Create your models here. class Book(models.Model): title=mod
阿强Wwlt
2018/07/09
8920
Python进阶43-drf框架(五)
-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。
DriverZeng
2022/09/26
3.2K0
Python进阶43-drf框架(五)
Django Rest Framework
https://q1mi.github.io/Django-REST-framework-documentation/
vanguard
2020/07/07
2.4K0
用django写接口(实战篇)
博客:https://www.jianshu.com/u/9fcd71535294
陈宇明
2020/12/15
2.3K0
用django写接口(实战篇)
推荐阅读
相关推荐
Django+Vue开发生鲜电商平台之5.使用DRF实现商品列表页和过滤
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验