GreatSQL社區原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。 GreatSQL是MySQL的國產分支版本,使用上與MySQL一致。 作者: 王權富貴 文章來源:GreatSQL社區原創 背景 在一次日常測試中發現,kill 一個會話後,SQL語句依然在運行並沒終止;被kill的會話重 ...
- GreatSQL社區原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。
- GreatSQL是MySQL的國產分支版本,使用上與MySQL一致。
- 作者: 王權富貴
- 文章來源:GreatSQL社區原創
背景
在一次日常測試中發現,kill 一個會話後,SQL語句依然在運行並沒終止;被kill的會話重新連接並繼續執行原來的SQL語句。
測試
本次測試基於MySQL 8.0.27
1.創建測試表
create table t1 (id int, name varchar(30));
insert into t1 values (1,'a'),(2,'b');
2.開啟3個會話
session1 | session2 | session3 |
---|---|---|
begin; | ||
select * from t1; | ||
rename table t1 to t2; 【由於鎖等待,hang住】 | ||
show processlist; 【查看 processlist_id】 | ||
kill session2; | ||
【session2 重新連接並且繼續執行語句,處於鎖等待狀態】 | ||
show processlist; 【可以看到session2重新連接並繼續執行SQL】 | ||
commit; | ||
【rename 執行成功】 | ||
show tables; 【t1 被 rename 為 t2】 |
session1:開啟一個事務不提交
mysql> use test
Database changed
mysql>
mysql>
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t1;
+------+------+
| id | name |
+------+------+
| 1 | a |
| 2 | b |
+------+------+
2 rows in set (0.00 sec)
session2:執行DDL語句
mysql> use test
Database changed
mysql>
mysql>
mysql> rename table t1 to t2;
session3:kill session2
mysql> show processlist;
+-----+------+---------+---------+--------------------------------+----------------------+
| Id | db | Command | Time | State | Info |
+-----+------+---------+---------+--------------------------------+----------------------+
| 6 | NULL | Daemon | 4399013 | Waiting on empty queue | NULL |
| 132 | test | Sleep | 232 | | NULL |
| 134 | test | Query | 123 | Waiting for table metadata lock| rename table t1 to t2|
| 135 | test | Query | 0 | init | show processlist |
+-----+------+---------+---------+--------------------------------+----------------------+
4 rows in set (0.00 sec)
mysql> kill 134;
Query OK, 0 rows affected (0.01 sec)
#為了排版,表格欄位略有刪減,具體信息請看圖片
session2:session2重新連接,並且繼續執行DDL語句,仍處於鎖等待狀態
mysql> rename table t1 to t2;
ERROR 2013 (HY000): Lost connection to MySQL server during query
No connection. Trying to reconnect...
Connection id: 136
Current database: test
session3:查看會話信息
mysql> show processlist;
+-----+------+---------+---------+--------------------------------+----------------------+
| Id | db | Command | Time | State | Info |
+-----+------+---------+---------+--------------------------------+----------------------+
| 6 | NULL | Daemon | 4399260 | Waiting on empty queue | NULL |
| 132 | test | Sleep | 479 | | NULL |
| 135 | test | Query | 0 | init | show processlist |
| 136 | test | Query | 193 | Waiting for table metadata lock| rename table t1 to t2|
+-----+------+---------+---------+--------------------------------+----------------------+
4 rows in set (0.00 sec)
#為了排版,表格欄位略有刪減,具體信息請看圖片
可以看到, kill session2 後,session2 重新連接並且繼續執行SQL
session1:提交事務
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
session2:執行成功
mysql> use test
Database changed
mysql>
mysql>
mysql> rename table t1 to t2;
ERROR 2013 (HY000): Lost connection to MySQL server during query
No connection. Trying to reconnect...
Connection id: 136
Current database: test
Query OK, 0 rows affected (8 min 38.00 sec)
通過上述測試,可以看到明明執行了 kill 命令,但是依然沒有達到我們想要的效果,似乎 kill 命令沒有生效一樣。
經過查詢資料發現,由於通過MySQL客戶端登錄,--reconnect
重新連接選項預設是開啟的,該選項在每次連接丟失時都會進行一次重新連接嘗試;因此在kill session2 後,session2重新連接並再次執行之前的SQL語句,導致感覺 kill 命令沒有生效。
--reconnect Reconnect if the connection is lost. Disable with
--disable-reconnect. This option is enabled by default.
(Defaults to on; use --skip-reconnect to disable.)
解決
可以通過以下2種方式避免上述問題的發生:
1.執行kill query 命令
KILL QUERY
終止連接當前正在執行的語句,但保持連接本身不變
session3:執行 KILL QUERY
命令
mysql> show processlist;
+-----+------+---------+---------+--------------------------------+----------------------+
| Id | db | Command | Time | State | Info |
+-----+------+---------+---------+--------------------------------+----------------------+
| 6 | NULL | Daemon | 4401560 | Waiting on empty queue | NULL |
| 132 | test | Sleep | 11 | | NULL |
| 135 | test | Query | 0 | init | show processlist |
| 137 | test | Query | 3 | Waiting for table metadata lock| rename table t1 to t2|
+-----+------+---------+---------+--------------------------------+----------------------+
4 rows in set (0.00 sec)
mysql>
mysql> kill query 137;
Query OK, 0 rows affected (0.00 sec)
#為了排版,表格欄位略有刪減,具體信息請看圖片
session2:
mysql> rename table t1 to t2;
ERROR 1317 (70100): Query execution was interrupted
可以看到session2執行的語句已經被終止了,達到了我們想要的效果。
2.登錄mysql客戶端時加--skip-reconnect選項
--skip-reconnect
表示當連接丟失時不會進行重新連接的嘗試
session2:登錄時加 --skip-reconnect
選項
shell> mysql -uroot -p -h127.0.0.1 -P3306 --skip-reconnect
session3:執行 kill 命令
mysql> show processlist;
+-----+------+---------+---------+--------------------------------+----------------------+
| Id | db | Command | Time | State | Info |
+-----+------+---------+---------+--------------------------------+----------------------+
| 6 | NULL | Daemon | 4402073 | Waiting on empty queue | NULL |
| 132 | test | Sleep | 524 | | NULL |
| 135 | test | Query | 0 | init | show processlist |
| 139 | test | Query | 4 | Waiting for table metadata lock| rename table t1 to t2|
+-----+------+---------+---------+--------------------------------+----------------------+
4 rows in set (0.00 sec)
mysql> kill 139;
Query OK, 0 rows affected (0.00 sec)
session2:
mysql> rename table t1 to t2;
ERROR 2013 (HY000): Lost connection to MySQL server during query
可以看到session2的會話連接已經被終止,並且沒有自動重新連接,達到了我們想要的效果。
總結
-
通過MySQL客戶端登錄時,會話重新連接的選項
--reconnect
預設是開啟的,如果要禁止重新連接可在登錄時添加 --skip-reconnect -
KILL CONNECTION
與KILL
相同,它在終止連接正在執行的任何語句後,再終止會話連接。 -
KILL QUERY
終止連接當前正在執行的語句,但保持連接本身不變。
參考鏈接
https://dev.mysql.com/doc/refman/8.0/en/kill.html
https://dev.mysql.com/doc/refman/8.0/en/mysql-command-options.html
Enjoy GreatSQL