1 引言
MySQL 中的 kill 语句的使用非常广泛,最常用的场景是处理慢 SQL。
不过 kill 语句实际上支持两种语法,适用于不同的场景,本文将进行介绍。
本文的主要内容包括:
-
介绍 kill 命令的语法、原理与适用场景 -
结合真实案例,分别在生产环境与测试环境中使用两种 kill 命令
2 介绍
2.1 语法
kill 命令的语法如下所示。
KILL [CONNECTION | QUERY] processlist_id
其中包括 kill 关键字与 processlist_id 变量,并支持两种修饰符,包括 CONNECTION 与 QUERY。
kill 语句的理论基础是 MySQL 中每个连接对应一个独立的线程,因此 MySQL 有类似 Linux 的 kill 命令很合理。
Each connection to mysqld runs in a separate thread. You can kill a thread with the KILL processlist_id statement.
下面介绍下两种 kill 命令的区别:
-
kill query + 线程 id,表示终止这个线程中正在执行的语句; -
kill connection + 线程 id,其中 connection 可缺省,表示断开这个线程的连接,如果线程中有语句正在执行,会先停掉正在执行的语句。
大多数情况下,kill query/connection 命令有效,比如使用 kill query 终止大查询。
特殊场景下也会遇到 kill 不掉的情况,而要分析原因就需要先了解 kill 命令的原理。
2.2 原理
简单介绍 kill 命令的原理,从中也可以看到两种 kill 语句的区别。
首先,收到 kill 命令以后,会直接终止掉线程吗?
答案是不行,直接终止线程的话,如果该线程还持有元数据锁的 MDL 锁,就没有机会释放锁了。
比如增删改查时需要给表加 MDL 读锁,如果由于等待行锁处于 blocked 状态, 但仍持有 MDL 读锁。
因此,实际上,使用 kill 语句时,并不是马上停止的意思,而是告诉执行线程语句已经不需要再执行,可以开始“执行停止的逻辑了”。
其实,这跟 Linux 的 kill 命令类似,kill -N pid 并不是让进程直接停止,而是给进程发一个信号,然后进程处理这个信号,进入终止逻辑。只是对于 MySQL 的 kill 命令来说,不需要传信号量参数,就只有“停止”这个命令。
执行 kill query 时,MySQL 中处理 kill 命令的线程做了两件事:
-
将 session 的运行状态修改为 THD::KILL_QUERY; -
给 session 的执行线程发送一个终止信号。发送终止信号的作用是唤醒线程退出等待,处理 THD::KILL_QUERY 状态。
MySQL 是典型的多线程应用,而信号是线程间通信的一种方式。
线程如何处理 THD::KILL_QUERY 状态呢?
-
一个语句执行过程中有多处“埋点”,在这些“埋点”的地方判断线程状态,如果发现线程状态是 THD::KILL_QUERY,才开始进入语句终止逻辑; -
如果处于等待状态,必须是一个可以被唤醒的等待,否则根本不会执行到“埋点”处; -
语句从开始进入终止逻辑,到终止逻辑完全完成,是有一个过程的。
kill connection 的作用是什么呢?
执行 kill connection 命令时,MySQL 中处理 kill 命令的线程做了两件事:
-
将线程的运行状态修改为 KILL_CONNECTION; -
关掉线程的网络连接,因此 session 将收到断开连接的提示。
kill connection 本质上只是把客户端的 SQL 连接断开,后面的执行流程还是要走 kill query 的。
额外的一个不同就是 show processlist 的时候,kill connection 会显示 “killed”。
原因是执行 show processlist 命令时,如果线程的状态是 KILL_CONNECTION,就将 Command 列显示成 Killed。
上面提到,如果线程处于无法被唤醒的状态,也就无法判断线程的状态,因此不会进入终止逻辑阶段。
下面分别介绍两个案例,其中第一个 kill query 有效,第二个 kill query 无效,kill connection 有效。
2.3 测试案例
2.3.1 kill query 有效
如下所示,当语句处于锁等待过程时使用 kill query 命令有效。
session A | session B | session C |
---|---|---|
begin; update t3 set a=0 where id=1; |
||
update t3 set a=0 where id=1; (blocked) |
||
ERROR 2013 (HY000): Lost connection to MySQL server during query | kill query thread_id_B; |
查看锁等待关系,结果显示 session B 在等待表的行锁,具体是 10296015 事务在等待 10296014 事务持有的表空间 id=48 的数据表的主键索引中数据页 page_no=3 上主键 id=1 数据行上的行锁。
mysql> select * from information_schema.innodb_locks;
+-----------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+-----------+
| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |
+-----------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+-----------+
| 10296015:48:3:2 | 10296015 | X | RECORD | `test_zk`.`t3` | PRIMARY | 48 | 3 | 2 | 1 |
| 10296014:48:3:2 | 10296014 | X | RECORD | `test_zk`.`t3` | PRIMARY | 48 | 3 | 2 | 1 |
+-----------------+-------------+-----------+-----------+----------------+------------+------------+-----------+----------+-----------+
2 rows in set, 1 warning (0.00 sec)
mysql>
mysql> select * from information_schema.innodb_lock_waits;
+-------------------+-------------------+-----------------+------------------+
| requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id |
+-------------------+-------------------+-----------------+------------------+
| 10296015 | 10296015:48:3:2 | 10296014 | 10296014:48:3:2 |
+-------------------+-------------------+-----------------+------------------+
1 row in set, 1 warning (0.00 sec)
查看事务信息,结果显示 10296015 事务发生锁等待,获取到了意向锁(Intention Lock),等待 10296014 事务中持有的行锁(lock_mode X locks rec but not gap,Record Lock)已经 50 秒。
mysql> show engine innodb status G
...
------------
TRANSACTIONS
------------
Trx id counter 10296016
Purge done for trx's n:o < 10296014 undo n:o < 0 state: running but idle
History list length 58
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 422165848318464, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 422165848316640, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
# 10296015 事务,等待锁
---TRANSACTION 10296015, ACTIVE 50 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 1062, OS thread handle 140689372804864, query id 10769253 127.0.0.1 admin updating
update t3 set a=0 where id=1
------- TRX HAS BEEN WAITING 50 SEC FOR THIS LOCK TO BE GRANTED: # 等待锁50秒
RECORD LOCKS space id 48 page no 3 n bits 568 index PRIMARY of table `test_zk`.`t3` trx id 10296015 lock_mode X locks rec but not gap waiting # 等待行锁
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000001; asc ;;
1: len 6; hex 0000009d1ace; asc ;;
2: len 7; hex 620000003b0239; asc b ; 9;;
3: len 4; hex 80000000; asc ;;
4: len 4; hex 74657374; asc test;;
------------------
TABLE LOCK table `test_zk`.`t3` trx id 10296015 lock mode IX # intention lock
RECORD LOCKS space id 48 page no 3 n bits 568 index PRIMARY of table `test_zk`.`t3` trx id 10296015 lock_mode X locks rec but not gap waiting # 等待行锁
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000001; asc ;;
1: len 6; hex 0000009d1ace; asc ;;
2: len 7; hex 620000003b0239; asc b ; 9;;
3: len 4; hex 80000000; asc ;;
4: len 4; hex 74657374; asc test;;
# 10296014 事务,持有锁
---TRANSACTION 10296014, ACTIVE 55 sec
2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1
MySQL thread id 1061, OS thread handle 140689507792640, query id 10769251 127.0.0.1 admin
TABLE LOCK table `test_zk`.`t3` trx id 10296014 lock mode IX # intention lock
RECORD LOCKS space id 48 page no 3 n bits 568 index PRIMARY of table `test_zk`.`t3` trx id 10296014 lock_mode X locks rec but not gap # 持有行锁
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
0: len 4; hex 80000001; asc ;;
1: len 6; hex 0000009d1ace; asc ;;
2: len 7; hex 620000003b0239; asc b ; 9;;
3: len 4; hex 80000000; asc ;;
4: len 4; hex 74657374; asc test;;
...
其中:
-
意向锁是特殊的表锁,相互之间不冲突,包括 intention share lock(IS)和intention exclusive lock(IX); -
lock_mode X = next-key lock = record lock + gap lock。该案例中 SQL 是唯一索引的等值查询,因此仅需要 record lock,不需要 gap lock。
查看元数据锁,结果显示 session A 与 session B 都已经获取(GRANTED)到了元数据锁,这也符合加锁的粒度从大到小的原则。
mysql> select object_type,object_schema,object_name,lock_type,lock_duration,lock_status,owner_thread_id from performance_schema.metadata_locks;
+-------------+--------------------+----------------+---------------------+---------------+-------------+-----------------+
| object_type | object_schema | object_name | lock_type | lock_duration | lock_status | owner_thread_id |
+-------------+--------------------+----------------+---------------------+---------------+-------------+-----------------+
| TABLE | test_zk | t3 | SHARED_WRITE | TRANSACTION | GRANTED | 1086 |
| GLOBAL | NULL | NULL | INTENTION_EXCLUSIVE | STATEMENT | GRANTED | 1087 |
| TABLE | test_zk | t3 | SHARED_WRITE | TRANSACTION | GRANTED | 1087 |
| TABLE | performance_schema | metadata_locks | SHARED_READ | TRANSACTION | GRANTED | 1084 |
+-------------+--------------------+----------------+---------------------+---------------+-------------+-----------------+
4 rows in set (0.00 sec)
在介绍完 kill query 有效的案例后,再介绍一个 kill query 无效的案例。
2.3.2 kill query 无效
首先,执行 set global innodb_thread_concurrency = 2,将 InnoDB 的并发线程上限数设置为 2。
innodb_thread_concurrency 参数用于限制 InnoDB 中的最大线程数。
默认值为 0,表示不限制,大于 0 时,表示将在 Server 层调用 InnoDB 接口前检查已经接收的请求线程数。
如果已经超过 innodb_thread_concurrency 限制,新请求线程将进入 FIFO 队列等待唤醒。
然后,执行下面的操作,当第三个 session 中执行 select 语句时发生阻塞。
经验证,kill query 无效,kill connection 有效。
session A | session B | session C | session D | session E |
---|---|---|---|---|
select sleep(100) from t3; | select sleep(100) from t3; | |||
select * from t3; (blocked) |
||||
kill query C; | ||||
ERROR 2013 (HY000): Lost connection to MySQL server during query | kill C; |
查看锁等待关系,结果显示没有发生锁等待。
mysql> select * from information_schema.innodb_locks;
Empty set, 1 warning (0.00 sec)
在客户端断开连接以后,id=1065 线程的 Command 列显示 Killed,表明服务端上这条语句还在执行中。
mysql> SHOW PROCESSLIST;
+------+------------+-----------------+---------+-------------+---------+---------------------------------------------------------------+---------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+------+------------+-----------------+---------+-------------+---------+---------------------------------------------------------------+---------------------------+
| 1049 | replicater | 127.0.0.1:42474 | NULL | Binlog Dump | 1362674 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 1063 | admin | 127.0.0.1:56953 | test_zk | Query | 72 | User sleep | select sleep(100) from t3 |
| 1064 | admin | 127.0.0.1:57077 | test_zk | Query | 70 | User sleep | select sleep(100) from t3 |
| 1065 | admin | 127.0.0.1:57190 | test_zk | Killed | 67 | Sending data | select * from t3 |
| 1066 | admin | 127.0.0.1:34796 | test_zk | Query | 0 | starting | SHOW PROCESSLIST |
+------+------------+-----------------+---------+-------------+---------+---------------------------------------------------------------+---------------------------+
5 rows in set (0.00 sec)
为什么同样使用 kill query 命令,第一个例子中 update 语句有效,而这个例子中 select 语句无效?
在实现上,等行锁时,使用的是 pthread_cond_timedwait 函数,这个等待状态可以被唤醒。但是,在这个例子里,1065 号线程的等待逻辑是这样的:每 10 毫秒判断一下是否可以进入 InnoDB 执行,如果不行,就调用 nanosleep 函数进入 sleep 状态。
因此,尽管 1065 号线程的状态已经被修改为 KILL_QUERY,但是在这个等待进入 InnoDB 的循环过程中,并没有去判断线程的状态,因此根本不会进入终止逻辑阶段。虽然语句执行过程中有多处“埋点”,但是由于超出并发限制,导致 1065 号线程无法获取到执行权,因此 kill query 无效。
而执行 kill connection 命令时,首先将线程状态修改为 KILL_CONNECTION,然后关掉 1065 号线程的网络连接,因此 session C 收到了断开连接的提示。
而在客户端退出以后,这个线程的状态仍然是在等待中。那这个线程什么时候会退出呢?
答案是,只有等到满足进入 InnoDB 的条件后,session C 的查询语句继续执行,然后才有可能判断到线程状态已经变成了 KILL_QUERY 或者 KILL_CONNECTION,再进入终止逻辑阶段。
因此,在该案例中在客户端退出以后,直到 session A 或 session B 执行结束以后,1065 号线程才能在获取到执行权后退出。
如下所示,session C 在 kill 后还等待了超过 1000 秒。
mysql> SHOW PROCESSLIST;
+------+------------+-----------------+---------+-------------+---------+---------------------------------------------------------------+---------------------------+
| Id | User | Host | db | Command | Time | State | Info |
+------+------------+-----------------+---------+-------------+---------+---------------------------------------------------------------+---------------------------+
| 1063 | admin | 127.0.0.1:56953 | test_zk | Query | 1058 | User sleep | select sleep(100) from t3 |
| 1064 | admin | 127.0.0.1:57077 | test_zk | Query | 1056 | User sleep | select sleep(100) from t3 |
| 1070 | admin | 127.0.0.1:37863 | test_zk | Killed | 1033 | Sending data | select * from t3 |
+------+------------+-----------------+---------+-------------+---------+---------------------------------------------------------------+---------------------------+
3 rows in set (0.00 sec)
注意 sleep(100) 并不表示全表暂停 100 秒,而是指每行暂停 100 秒。sleep 函数常用于模拟死锁现象。
因此,当表中数据有 11 行时,全表暂停 1100 秒,约等于 18 分钟。
# session A
mysql> select sleep(100) from t3;
...
11 rows in set (18 min 19.83 sec)
# session B
mysql> select sleep(100) from t3;
...
11 rows in set (18 min 19.84 sec)
如果仅使用 sleep(100) 函数,表示仅暂停 100 秒。
mysql> select sleep(100);
+------------+
| sleep(100) |
+------------+
| 0 |
+------------+
1 row in set (1 min 39.99 sec)
在介绍了两个案例,对于 kill 命令有了感性认识后,总结下 kill 命令的适用场景。
2.4 总结
2.4.1 ”埋点“
上面提到,kill 命令生效的前提是执行到“埋点”,然后在这些“埋点”的地方判断线程状态。如果发现线程状态是 THD::KILL_QUERY,才开始进入语句终止逻辑。
因此,有可能线程状态已经修改为 KILL_QUERY 或者 KILL_CONNECTION,但由于无法进入终止逻辑阶段,最终导致 kill 失效。
下面介绍下不同场景下判断线程状态的“埋点”位置:
-
select 语句,如果有 order by 或 group by 循环,每读取若干行(a block of rows)检查一次线程状态,发现 kill flag 后将立即终止语句; -
alter table 语句,如果需要拷贝表,每复制若干行检查一次线程状态,发现 kill flag 后将终止语句,不过删除临时文件需要时间; -
update、delete 语句,每更新若干行检查一次线程状态,发现 kill flag 后将立即终止语句,不过回滚的前提是开启事务; -
线程等待表锁(State: Locked),发现 kill flag 后表锁会立即释放; -
线程写入过程中等待磁盘剩余空间,发现 kill flag 后将立即放弃写入并返回报错“disk full”。
2.4.2 kill 无效场景
注意这里所说的 kill 无效不代表无法 kill,而是特指 kill 以后线程没有立即退出。
主要包括以下两种情况:
-
线程没有执行到判断线程状态的逻辑,比如超过 innodb_thread_concurrency 并发限制、IO 压力较大时导致读写 IO 的函数一直无法返回,无法及时判断线程的状态; -
终止逻辑耗时较长,从 show processlist 结果上看也是 Command=Killed,需要等到终止逻辑完成,语句才算真正完成。常见的场景包括: -
超大事务执行期间被 kill,回滚用时长; -
大查询回滚,如果查询过程中生成了比较大的临时文件,加上此时文件系统压力大,删除临时文件可能需要等待 IO 资源,导致耗时较长; -
DDL 命令执行到最后阶段,如果被 kill,需要删除中间过程的临时文件,也可能受 IO 资源影响耗时较久。
其中,对于线程没有执行到判断线程状态的逻辑的场景,kill query 无效,只能使用 kill connection。
但是,实际工作中也遇到过 kill connection 无效的场景,具体将新开一篇讲解。
2.4.3 Ctrl + C
如果直接在客户端执行 Ctrl + C 命令,可以直接终止线程吗?
答案是不可以。原因是客户端的操作只能操作到客户端的线程,客户端与服务端只能通过网络交互,不可能直接操作服务端线程。
因此,实际上执行 Ctrl + C 命令时,MySQL 客户端会另外创建一个连接,然后发送 kill query 命令。
MySQL 客户端与服务端之间的通信协议是“半双工”的,因此,在任何时刻,要么是由服务端向客户端发送数据,要么是由客户端向服务端发送数据,这两个动作不能同时发生。
一旦一端开始发送消息,另一端要接受完整个消息才能响应它。因此,一旦客户端发送了请求,它能做的事情就只是等待结果了,在线程执行的语句返回之前,再往这个连接里面继续发命令也是没有用的。
3 线上案例
研发在创建数据出库任务过程时,在数据写入前删除过期数据。
一小时后,任务始终卡着不动,分析日志发现卡在 delete 语句,因此联系 DBA 进行处理。
3.1 kill query
如下所示,delete 语句已经执行了 8740 秒,是一条以时间为条件的删除语句。
mysql> select * from information_schema.processlist where info is not null and time>600;
+--------+---------+----------------------+-------------+---------+------+-----------+------------------------------------------------------------------------------------+
| ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO |
+--------+---------+----------------------+-------------+---------+------+-----------+------------------------------------------------------------------------------------+
| 707252 | bi_dw_w | x.x.x.x:60670 | digitaltwin | Query | 8740 | query end | delete from digitaltwin.warehouse_zone_cell_type where record_date <= '2022-08-25' |
+--------+---------+----------------------+-------------+---------+------+-----------+------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
经查看,该表数据行数超过一亿行,因此执行完成需要很长时间,因此决定 kill 掉该语句。
如下所示,使用 kill query 命令无效,不过具体原因还有待分析。
mysql> kill query 707252;
Query OK, 0 rows affected (0.00 sec)
mysql>
mysql> select * from information_schema.processlist where info is not null and time>600;
+--------+---------+----------------------+-------------+---------+------+-----------+------------------------------------------------------------------------------------+
| ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO |
+--------+---------+----------------------+-------------+---------+------+-----------+------------------------------------------------------------------------------------+
| 707252 | bi_dw_w | x.x.x.x:60670 | digitaltwin | Query | 8748 | query end | delete from digitaltwin.warehouse_zone_cell_type where record_date <= '2022-08-25' |
+--------+---------+----------------------+-------------+---------+------+-----------+------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
3.2 kill connection
使用 kill connection 命令有效,kill 完成后 Command=killed,超大事务开始基于 undo log 回滚。
mysql> kill connection 707252;
Query OK, 0 rows affected (0.00 sec)
mysql>
mysql> select * from information_schema.processlist where info is not null and time>600;
+--------+---------+----------------------+-------------+---------+------+-----------+------------------------------------------------------------------------------------+
| ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO |
+--------+---------+----------------------+-------------+---------+------+-----------+------------------------------------------------------------------------------------+
| 707252 | bi_dw_w | x.x.x.x:60670 | digitaltwin | Killed | 8798 | query end | delete from digitaltwin.warehouse_zone_cell_type where record_date <= '2022-08-25' |
+--------+---------+----------------------+-------------+---------+------+-----------+------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
3.3 业务场景
在 kill 了 delete 语句以后,研发最终是如何解决该问题的呢?
经了解,最终使用 truncate 命令清空全表,因此前后使用的 SQL 语句如下所示。
# killed, > 8798s
delete from digitaltwin.warehouse_zone_cell_type where record_date <= '2022-08-25';
# success, 2.44s
truncate table warehouse_zone_cell_type;
那么,为什么直接使用 truncate 命令可行?实际上,这是一种临时方案。
业务的数据链路为:MySQL 生产库- hive -MySQL 报表库,其中该实例是报表库。
hive 中不同的表可能会有不同的上游,在 hive 这个环境中,还会经过若干次数据加工。
当前向报表库中同步了全量数据,共有全国的 1000 多个仓的数据,但实际系统中在应用的仓仅十几个。
因此选择了在第一次清空表以后,每次仅同步需要的数据,写入之前需要删除的数据也就变少了。
但是这样不是长久之计,随着应用的仓越来越多,最终还是需要全量同步。
可是,为什么不直接查询 hive 呢?
首先研发没有上游 MySQL 生产库的权限,因此只能访问到 hive。
但是查询 hive 表时接口不稳定,导致查询失败的概率很高,大数据的同事反馈是查询引擎的问题。
因此业务最终选择将 hive 中需要的数据同步回 MySQL 中,使用 MySQL 进行报表查询。
既然 delete 比较慢,配置定时结转是否可行?
不一定适用,原因是有可能一条 delete 语句执行了 4 个小时还没完成,而且删除过程中空间未释放,还没删除完成之前就可能导致磁盘打满。
因此业务选择分表,这样就需要选择分表策略,并避免数据倾斜问题,即多表的数据不会差太多。
4 知识点
4.1 client & server
MySQL 基于网络的客户端 / 服务端架构运行,也就是传统的 C/S 架构。
Linux 系统中 MySQL 支持以下两种通信协议:
-
Unix Socket 协议,用于本地连接数据库,语法为 mysql -S /tmp/mysql.sock,基于本地套接字文件;
socket 是一种内部进程通信形式,它被用于在相同主机上形成进程间的双向通信连接点(在本地系统上的一个物理文件)。
-
TCP/IP 协议,用于远程连接数据库,语法为 mysql -u -p -h -P,基于 IP 地址串。可以通过在服务端程序(mysqld)的启动命令中添加 skip-networking 参数禁止客户端使用 TCP/IP 协议进行通信。
传输控制协议(Transmission Control Protocol)/ 互联网协议(Internet Protocol),是一套被用于连接互联网上各主机的通信协议。TCP/IP 一开始是用于 UNIX 操作系统建立互联网通信的,现在它已经成为了一种网络数据传输的事实标准。
如下所示,分别使用两种方式连接数据库。
# socket
/export/servers/mysql/bin/mysql -S /export/zhangkai321/mysql/3341/tmp/mysql.sock
# TCP/IP
/export/servers/mysql/bin/mysql -uadmin -p3341 -h 127.0.0.1 -P 3341
使用s
命令分别查看两种连接方式创建的连接。
# socket
mysql> s
...
Current user: root@localhost # 本地
SSL: Not in use
Server version: 5.7.24-log Source distribution
Connection: Localhost via UNIX socket
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
UNIX socket: /export/zhangkai321/mysql/3341/tmp/mysql.sock
Uptime: 144 days 21 hours 18 min 53 sec
# TCP/IP
mysql> s
Current user: admin@127.0.0.1 # 远程
SSL: Not in use
Server version: 5.7.24-log Source distribution
Connection: 127.0.0.1 via TCP/IP
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
TCP port: 3341
Uptime: 144 days 21 hours 19 min 7 sec
4.2 server & engine
如下图所示,MySQL 架构中包括 Server 层与存储引擎层。
其中:
-
Server 层,负责不涉及读写表数据的操作,如连接管理、解析与优化。所有跨存储引擎的功能都在 Server 层实现,如存储过程、触发器、视图等。Server 层即 MySQL server 或 mysqld,实际上是一个数据库服务器程序; -
存储引擎层,负责读写表数据,存储引擎可以理解为文件系统,用于管理磁盘上的数据文件。采用插件式架构模式,支持 InnoDB、MyISAM 等多种存储引擎。Server 层通过 API 与存储引擎进行通信,接口可以屏蔽不同存储引擎之间的差异。
实际上,与其他数据库系统相比,MySQL 最重要、最与众不同的特性就是它的存储引擎架构,这种架构的设计将查询处理(Query Processling)及其他系统任务(Server Task)和数据的存储 / 提取相分离。
5 结论
MySQL 中每个连接对应一个独立的线程,因此 MySQL 中支持类似 Linux 的 kill 命令。
具体包括两种 kill 命令,包括 kill query 与 kill connection。
两者的主要区别是 kill connection 会将客户端的 SQL 连接断开,并在执行 show processlist 时,Command 列会显示 “killed”。
实际工作中,kill connection 会使用的比较多,原因是如果线程没有执行到判断线程状态的逻辑的场景,kill query 无效。
除此之外,生产环境中也遇到过 kill connection 无效的情况,具体将在单独一篇文章中介绍。
尽管原则上 MySQL 适用 TP(Transaction Processing),AP(Analytical Processing) 查询建议使用专门设计的数据库,比如数据仓库(Data Warehouse),而 hive 正是基于 hadoop 实现的数据仓库。
但是在实际业务中,如果无法保证查询的稳定性与查询效率,有可能业务最终还是选择使用传统的 MySQL 完成 HTAP,因此新型数据库在替代 MySQL / Oracle 之前需要首先保证服务的稳定性。
6 待办
-
分表策略 -
锁 -
信号 -
connection & session
参考教程
-
《MySQL 实战 45 讲》为什么还有kill不掉的语句?
-
《MySQL 5.7 Reference Manual》KILL Statement
-
mysql中的 kill,详解MySQL kill 指令的执行原理
原文始发于微信公众号(丹柿小院):MySQL 两种 kill 语法
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/194460.html