kill 命令之后MySQL都做了哪些

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 大家好,我是Leo。目前在常州从事Java后端开发的工作。上一篇我们介绍了线上数据库误删数据后,到底是跑路还是该如何解决!这一篇我们介绍一下为什么我们在调试SQL的时候会出现Kill不掉线程的情况。

思路


本篇文章的介绍思路以下图的思维导图为大纲。也有利于读者更好的分辨可读性!

image.png


为什么需要kill


测试

从测试方面考虑的话,就是我们在写SQL语句的时候。开始寻找不足点,有些时候会偶然间执行一个大事务,这个时候我们为了提升效率往往会直接干到这个查询

生产

随着数据量爆发式的增长,一些查询功能越来越慢的。而我们在调试一个功能的时候往往就是调试背后的SQL语句。还有一种情况就是,修改表结构的时候,由于数据量过大,我们会放弃普遍方法,会寻找一个快速的方法。

锁等待

比如发生死锁的时候,或者两个锁在争锁的时候。往往会需要kill。结束掉一个事务给事务回滚放行另一个事务


kill内部都做了啥


首先介绍两种kill写法吧

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

言归正传

前几篇文章我们介绍过,对一个表进行增删改查的时候,会在表上加一个读锁。这个时候用户虽然处于blocked状态,但是还拿着MDL读锁。如果线程直接被kill的话,读锁就没办法释放了。所以最理想的状态应该是,kill之后,让他做一些收尾工作,全部结束之后再结束掉线程。

那么它到底做了啥

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

流程扩展

我们继续按照上述的流程作一个扩展。为什么要发信号呢?

举一个多用户请求的例子。如果用户A处于锁等待状态,如果只是把用户A的线程状态设置为THD::KILL_QUERY ,线程A并不知道这个状态变化,还是会继续等待。发一个信号的目的,就是让 用户A 退出等待,来处理这个 THD::KILL_QUERY 状态。

换言之。如果发现线程状态是THD::KILL_QUERY 才开始进入语句终止逻辑。


kill不掉是啥鬼


首先我们介绍一个参数,控制线程并发上限的这个参数innodb_thread_concurrency 举例说明一下

  • sessionA:select sleep(100) from t
  • sessionB:select sleep(100) from t
  • sessionC:select sleep(100) from t (blocked)
  • sessionD:kill query C
  • sessionE:kill C <=> kill connection C

通过上述5个用户的执行,我们先把他设置成set global innodb_thread_concurrency=2 可以看到

  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,你就能看到下面这个图。

image.png

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

为什么在执行 kill query 命令时,不像 update 语句一样退出呢?

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

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

而当 session E 执行 kill connection 命令时

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

show processlist 隐藏逻辑 如果一个线程的状态是KILL_CONNECTION,就把Command列显示成Killed。

所以在show processlist列表中会把connection改成killed,也就是我们看到的状态。

综上所述 kill无效的几种情况:

  • 线程没有执行到判断线程状态的逻辑

跟这种情况相同的,还有由于 IO 压力过大,读写 IO 的函数一直无法返回,导致不能及时判断线程的状态。

  • 终止逻辑耗时较长

从 show processlist 结果上看也是 Command=Killed,需要等到终止逻辑完成,语句才算真正完成。比如超大事务被kill需要做很多回收查找,大查询回滚,DDL命令。

我们可以对大查询回滚做一个扩展介绍,前几篇文章我们介绍过查询数据的时候,当数据量超过一个数量的时候我们会采用硬盘存储,如果小于这个数量的时候会采用内存存储。所以如果在磁盘中查询的时候。进行回滚!相应的磁盘页也会消耗一定的时间去关闭释放。


客户端与服务端的关闭问题


Ctrl+C 关闭的什么

客户端的操作只能操作到客户端的线程,客户端和服务端只能通过网络交互,是不可能直接操作服务端线程的。而由于 MySQL 是停等协议,所以这个线程执行的语句还没有返回的时候,再往这个连接里面继续发命令也是没有用的。实际上,执行 Ctrl+C 的时候,是 MySQL 客户端另外启动一个连接,然后发送一个 kill query 命令。

所以,你可别以为在客户端执行完 Ctrl+C 就万事大吉了。因为,要 kill 掉一个线程,还涉及到后端的很多操作。

数据表过多会影响性能吗

我们在第一篇文章就介绍了每个客户端和服务器建立连接时,做了哪些事情。比如TCP握手,用户校验,获取权限等

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

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

最耗时的也就是第三步的哈希表构建了,也就是说,我们感知到的连接过程慢,其实并不是连接慢,也不是服务端慢,而是客户端慢

-A,-quick 可以跳过这个阶段。为什么这么说呢,我们可以介绍一下 -quick参数涉及的MySQL配置。

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

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

MySQL 客户端默认采用第一种方式,而如果加上–quick 参数,就会使用第二种不缓存的方式。

采用不缓存的方式时,如果本地处理得慢,就会导致服务端发送结果被阻塞,因此会让服务端变慢

扩展

为什么取名为quick呢?

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

综上所述:quick是提升客户端的性能,不是提升服务端的性能


总结


今天大概介绍了MySQL内部在kill线程的时候,都做了哪些操作以及强化了最开始的文章深度。

这里的文章深度主要是在哈希表构建的那一段。


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
存储 关系型数据库 MySQL
初步了解MySQL数据库的基本命令
初步了解MySQL数据库的基本命令
44 0
|
1月前
|
tengine 关系型数据库 MySQL
Tengine、Nginx安装MySQL数据库命令教程
本指南详细介绍了在Linux系统上安装与配置MySQL数据库的步骤。首先通过下载并安装MySQL社区版本,接着启动MySQL服务,使用`systemctl start mysqld.service`命令。若启动失败,可尝试使用`sudo /etc/init.d/mysqld start`。利用`systemctl status mysqld.service`检查MySQL的服务状态,确保其处于运行中。通过日志文件获取初始密码,使用该密码登录数据库,并按要求更改初始密码以增强安全性。随后创建一个名为`tengine`的数据库,最后验证数据库创建是否成功以及完成整个设置流程。
|
2月前
|
存储 关系型数据库 MySQL
MySQL基础命令及使用示例
这些基础命令构成了与MySQL数据库交互的核心,理解并掌握它们对于进行有效的数据库操作至关重要。在实际使用中,建议结合实际案例和需求来练习这些命令,以加深理解和提高效率。
30 3
|
2月前
|
存储 关系型数据库 MySQL
MySQL基础命令及使用示例
这些基础命令构成了与MySQL数据库交互的核心,理解并掌握它们对于进行有效的数据库操作至关重要。在实际使用中,建议结合实际案例和需求来练习这些命令,以加深理解和提高效率。
67 4
|
1月前
|
关系型数据库 MySQL 数据库
Mysql 常用命令
Mysql 常用命令
23 0
|
4月前
|
存储 关系型数据库 MySQL
(十五)MySQL命令大全:以后再也不用担心忘记SQL该怎么写啦~
相信大家在编写SQL时一定有一个困扰,就是明明记得数据库中有个命令/函数,可以实现自己需要的功能,但偏偏不记得哪个命令该怎么写了,这时只能靠盲目的去百度,以此来寻找自己需要的命令。
164 28
|
4月前
|
SQL 关系型数据库 MySQL
MySQL删除表数据、清空表命令(truncate、drop、delete 区别)
MySQL删除表数据、清空表命令(truncate、drop、delete区别) 使用原则总结如下: 当你不需要该表时(删除数据和结构),用drop; 当你仍要保留该表、仅删除所有数据表内容时,用truncate; 当你要删除部分记录、且希望能回滚的话,用delete;
|
4月前
|
SQL 关系型数据库 MySQL
mysql性能调优:EXPLAIN命令21
【7月更文挑战第21天】掌握SQL性能调优:深入解析EXPLAIN命令的神奇用法!
61 1
|
4月前
|
存储 SQL Cloud Native
云原生数据仓库使用问题之运行MySQL命令发现中文内容变成了问号,该如何解决
阿里云AnalyticDB提供了全面的数据导入、查询分析、数据管理、运维监控等功能,并通过扩展功能支持与AI平台集成、跨地域复制与联邦查询等高级应用场景,为企业构建实时、高效、可扩展的数据仓库解决方案。以下是对AnalyticDB产品使用合集的概述,包括数据导入、查询分析、数据管理、运维监控、扩展功能等方面。
|
5月前
|
NoSQL 关系型数据库 MySQL
linux服务器重启php,nginx,redis,mysql命令
linux服务器重启php,nginx,redis,mysql命令
120 1