(1)kill query +线程 id,终止正在执行;
(2)kill connection(可缺省) + 线程 id,断开连接(先停执行),
kill 没断开连接。show processlist 命令,显示Killed。不是应该看不到这个线程了吗?
有效场景:查询太久/锁等待
session B 被中断(符合预期)
一、收到 kill 以后,线程做什么?
第 6 篇文章增删改时,表加 MDL 读锁。 B 虽 blocked 但拿MDL 读锁。终止则没机会被释放。kill :不需执行
跟 Linux 的 kill 命令类似,kill -N pid 并不是让进程直接停止,而是给进程发一个信号,然后进程处理这个信号,进入终止逻辑。只是对于 MySQL 的 kill 命令来说,不需要传信号量参数,就只有“停止”这个命令。
1.1 kill query做了两件事:
(1)改状态:THD::KILL_QUERY(变量 killed 赋值为 THD::KILL_QUERY);
(2)发信号:让B知道。
多处“埋点”,判断状态THD::KILL_QUERY,进入终止逻辑(不是“说停就停的”);
ps:如等待,必须是可唤醒,否则不会执行到“埋点”;
1.2 kill 不掉的例子
(1)KILL_QUERY,等待中,不会进入终止逻辑阶段。
第 29 篇文章 set global innodb_thread_concurrency=2,并发线程上限数
session E 中执行 show processlist,断开连接,服务端仍在执行 ,不像第一个update 退出?
等行锁时用pthread_cond_timedwait 函数,等待状态可被唤醒。10 毫秒判断是否进 InnoDB 执行,不行调用 nanosleep 函数sleep 状态。
设置为KILL_CONNECTION;关掉网络连接。显示成 Killed。
IO 压力过大,读写 IO 无法返回,出现同样情况
(2)终止逻辑耗时较长
1. 超大事务执行期间被 kill。回滚长。
2. 大查询回滚。生成大临时文件,删除等 IO 资源,耗时长。
1.3客户端 Ctrl+C 不能终止线程
客户端和服务端只能通过网络交互,不能直接操作服务端线程。 kill 涉及后端很多
停等协议:没返回时,往连接里发命令没用。Ctrl+C :另外启动连接,发送 kill query 命令。
二、另外两个关于客户端的误解
2.1 误解1:表多,连接慢
库里6 万个表,客户端连接卡:
连接时: TCP 握手、用户校验、获取权限。跟表个数无关。
默认参数连接时,MySQL 提供本地库、表名补全功能(用的不多)。为了实现这个功能,连接成功多做操作:
show databases,切到 db1 库 show tables;上面结果构建本地哈希表(表多时间长,关掉补全就快)。
2.2 加–quick(简写为 -q) 跳过阶段,性能快(错)
可能降低服务端性能,接收服务端返回结果方式:
1. 缓存(默认),mysql_store_result 方法。
2. 不缓存(加–quick),mysql_use_result 方法。//本地处理得慢,发送结果阻塞,服务端慢。
2.3 quick 优点(让客户端变快)
(1)自动补全
(2)mysql_store_result 申请内存缓存结果,但查询结果大,耗费内存多,影响性能;
(3)不把执行命令记录到本地命令历史文件。
小结
“kill 不掉”是因为发送 kill 命令客户端,并没有强行停止目标线程执行,只是设置了个状态,并唤醒对应的线程。被 kill 线程,执行到判断状态的“埋点”,才进入终止逻辑阶段。
发现线程 Killed 状态,影响系统环境, Killed 状态尽快结束。
第一个例子里 InnoDB 并发度的问题,你就可以临时调大innodb_thread_concurrency 的值,或者停掉别的线程,让出位子给这个线程执行。
回滚逻辑由于受到 IO 资源限制,减少系统压力让它加速。
思考题
被 killed 事务一直回滚状态,强行重启,还是执行完成?为什么呢?
等待(更快),重启也要回滚,保证一致性
如果占用别的锁,或者占用 IO 资源过多,影响别语句执行,先做主备切换,切新主库
切换后别的线程都断开连接,自动停止执行。接下来还是等它自己执行完成。减少系统压力,加速终止逻辑。
评论1
kill connection:客户端sql连接断开,会显示“killed”。平时紧急处理用kill + thread_id
kill query:后面执行流程,不会回滚,ctrl+c时
kill query无效,kill connection也无效