两个 kill 命令

    1. kill query + 线程 id
    • 终止这个线程中正在执行的语句
    1. kill connection + 线程 id
    • connection 可以不写
    • 断开这个线程的连接
    • 会先停止正在执行的语句

收到 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);
      • 如果 session B 处于锁等待,并不能知道状态变化,还是会继续等待。
      1. 给 session B 的执行线程发一个信号。
      • 发信号的目的:让 session B 退出等待,处理 1 设置的状态

kill 无效的两类情况

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

    • 相同的还有由于 IO 压力过大,读写 IO 的函数一直无法返回,导致不能及时判断线程的状态
    • 语句执行到能判断到线程状态已经变成了 KILL_QUERY 或者 KILL_CONNECTION 的时候,再进入终止逻辑阶段。
    • 如果一个线程的状态是KILL_CONNECTION,就把Command列显示成Killed。
    1. 终止逻辑耗时较长

      1. 超大事务执行期间被 kill,触发回滚操作
      1. 大查询回滚,查询过程生成了比较大的临时文件 + 此时文件系统压力大 删除临时文件可能需要等待 IO 资源
      1. DDL 命令执行到最后阶段,被 kill 需要删除中间过程的临时文件,同 2

客户端执行 Ctrl+C

  • 是 MySQL 客户端另外启动一个连接发送一个 kill query 命令

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

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

    • 每个客户端在和服务端建立连接的时候,需要做的事情就是 TCP 握手、用户校验、获取权限。但这几个操作,跟库里面表的个数无关。(第一章)
    • 我们感知到的连接过程慢,其实并不是连接慢,也不是服务端慢,而是客户端慢。
      • 客户端在连接成功后:
        1. 执行 show databases
        2. 切到 db1 库,执行 show tables
        3. 把这两个命令的结果用于构建一个本地的哈希表(最耗时)
      • 如果在连接命令中加上 -A,就可以关掉这个自动补全的功能,然后客户端就可以快速返回。
      • –quick 也可以跳过
  • –quick

    • 是让客户端变快

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

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

      2. 另一种是不缓存,读一个处理一个。如果你用 API 开发,对应的就是 mysql_use_result 方法。

      • 默认第一种

        • 查询的返回结果不会很多的话,都推荐用这个
      • 加上 -quick 参数后使用第二种

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

    • 参数效果

        1. 跳过表名自动补全功能
        1. mysql_store_result 需要申请本地内存来缓存查询结果,如果查询结果太大,会耗费较多的本地内存
        1. 不会把执行命令记录到本地的命令历史文件

线程处于 Killed 状态

  • 可以做的事情:通过影响系统环境,让 Killed 状态尽快结束
  • 并发度问题,临时调大 innodb_thread_concurrency 的值或停掉别的线程,让出位子给这个线程执行
  • 回滚逻辑由于 IO 资源限制,通过减少系统压力让它加速

思考题

  • 如果你碰到一个被 killed 的事务一直处于回滚状态,你认为是应该直接把 MySQL 进程强行重启,还是应该让它自己执行完成呢?

    • 让它自己结束
  • 为什么呢?

    • 因为重启之后该做的回滚动作不能少
    • 可以先做主备切换,切到新主库提供服务
  • 减少系统压力,加速终止逻辑

评论区

  • 并非所有的 DDL 操作都可以通过主从切换来实现

    • 改索引、 加最后一列、删最后一列
    • 其他的大多数不行,比如删除中间一列
  • kill 的影响只有回滚,恢复到执行前的状态,没有其他

  • 遇到错误时:pstack > /tmp/pstack.1