MySQL -- KILL + 客戶端
摘要:
KILL QUERY THREAD_ID
終止這個執行緒中正在執行的語句
KILL [ CONNECTION ] THREAD_ID
斷開這個執行緒的連線,如果該執...
-
KILL QUERY THREAD_ID
- 終止這個執行緒中正在執行的語句
-
KILL [ CONNECTION ] THREAD_ID
- 斷開這個執行緒的連線,如果該執行緒有語句在執行,先停止正在執行的語句
鎖等待
表初始化
CREATE TABLE `t` ( `id` INT(11) NOT NULL, `c` INT(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB; INSERT INTO t VALUES (1,1);
操作次序
session A | session B | session C |
---|---|---|
BEGIN; | ||
UPDATE t SET c=c+1 WHERE id=1; | ||
UPDATE t SET c=c+2 WHERE id=1; (Blocked) |
||
SHOW PROCESSLIST; | ||
KILL QUERY 24; | ||
ERROR 1317 (70100): Query execution was interrupted |
mysql> SHOW PROCESSLIST; +----+-----------------+-----------+------+---------+--------+------------------------+-------------------------------+ | Id | User| Host| db| Command | Time| State| Info| +----+-----------------+-----------+------+---------+--------+------------------------+-------------------------------+ |4 | event_scheduler | localhost | NULL | Daemon| 472733 | Waiting on empty queue | NULL| | 21 | root| localhost | test | Sleep|130 || NULL| | 23 | root| localhost | test | Query|0 | starting| show processlist| | 24 | root| localhost | test | Query|5 | updating| UPDATE t SET c=c+2 WHERE id=1 | +----+-----------------+-----------+------+---------+--------+------------------------+-------------------------------+
KILL QUERY
- 對錶進行增刪改查 操作時,會在表上加MDL讀鎖
-
KILL QUERY
並不是馬上停止,而是告訴執行緒這條語句已經不需要再繼續執行 ,可以開始執行停止的邏輯kill -N pid
-
MySQL的具體動作
-
把
session B
的執行緒狀態改成THD:KILL_QUERY
(將變數killed
賦值為THD:KILL_QUERY
) -
給
session B
的執行執行緒發一個訊號-
session B
原本處於鎖等待狀態 - 如果只是修改執行緒狀態,執行緒B是不知道這個狀態的變化 的,還會繼續等待
-
發訊號的目的:讓
session B
退出等待,來處理THD:KILL_QUERY
狀態
-
-
把
-
隱含邏輯
-
一個語句在執行過程中會有多處埋點
,在這些埋點
的地方會判斷執行緒狀態
-
如果發現執行緒狀態為
THD:KILL_QUERY
,才開始進入語句終止 的邏輯
-
如果發現執行緒狀態為
- 如果處於等待狀態,必須是一個可以被喚醒的等待 ,否則根本不會執行到埋點處
- 語句從開始進入 終止邏輯,到完全完成 終止邏輯,是有個過程的
-
一個語句在執行過程中會有多處埋點
,在這些埋點
的地方會判斷執行緒狀態
併發執行緒數
SET GLOBAL innodb_thread_concurrency=2;
操作序列
session A | session B | session C | session D | session E |
---|---|---|---|---|
SELECT SLEEP(100) FROM t; | SELECT SLEEP(100) FROM t; | |||
SELECT * FROM t; (Blocked) |
||||
SHOW PROCESSLIST; (1st) |
||||
KILL QUERY 28; (無效) |
||||
KILL 28; | ||||
ERROR 2013 (HY000): Lost connection to MySQL server during query | ||||
SHOW PROCESSLIST; (2nd) |
-- 1st mysql> SHOW PROCESSLIST; +----+-----------------+-----------+------+---------+--------+------------------------+--------------------------+ | Id | User| Host| db| Command | Time| State| Info| +----+-----------------+-----------+------+---------+--------+------------------------+--------------------------+ |4 | event_scheduler | localhost | NULL | Daemon| 477650 | Waiting on empty queue | NULL| | 21 | root| localhost | test | Query|12 | User sleep| SELECT SLEEP(100) FROM t | | 24 | root| localhost | test | Query|8 | User sleep| SELECT SLEEP(100) FROM t | | 26 | root| localhost | test | Sleep|291 || NULL| | 27 | root| localhost | test | Query|0 | starting| SHOW PROCESSLIST| | 28 | root| localhost | test | Query|5 | Sending data| SELECT * FROM t| +----+-----------------+-----------+------+---------+--------+------------------------+--------------------------+ -- 2nd mysql> SHOW PROCESSLIST; +----+-----------------+-----------+------+---------+--------+------------------------+--------------------------+ | Id | User| Host| db| Command | Time| State| Info| +----+-----------------+-----------+------+---------+--------+------------------------+--------------------------+ |4 | event_scheduler | localhost | NULL | Daemon| 477667 | Waiting on empty queue | NULL| | 21 | root| localhost | test | Query|29 | User sleep| SELECT SLEEP(100) FROM t | | 24 | root| localhost | test | Query|25 | User sleep| SELECT SLEEP(100) FROM t | | 26 | root| localhost | test | Sleep|4 || NULL| | 27 | root| localhost | test | Query|0 | starting| SHOW PROCESSLIST| | 28 | root| localhost | test | Killed|22 | Sending data| SELECT * FROM t| +----+-----------------+-----------+------+---------+--------+------------------------+--------------------------+
KILL QUERY / CONNECTION
-
session C
執行的時候被堵住了,session D
執行KILL QUERY
沒啥效果-
等行鎖時,使用的是
pthread_cond_timedwait
函式,這個等待狀態是可以被喚醒 的 -
本例中,28號執行緒的等待邏輯為
-
每10ms
判斷下能否進入InnoDB執行,如果不行,呼叫
nanosleep
函式進入SLEEP
狀態
-
每10ms
判斷下能否進入InnoDB執行,如果不行,呼叫
-
雖然28號執行緒的狀態被設定成了
THD:KILL_QUERY
,但在等待進入InnoDB的迴圈過程中- 並沒有去判斷執行緒的狀態 ,因此根本不會進入終止邏輯 階段
-
等行鎖時,使用的是
-
session E
執行KILL CONNECTION
,斷開session C
的連線,Command
列變成了Killed
- 表示客戶端 雖然斷開了連線 ,但實際上服務端 上這條語句還是在執行中
-
把28號執行緒的狀態設定為
THD:KILL_CONNECTION
,然後關閉 12號執行緒的網路連線-
session C
會收到斷開連線的提示
-
-
SHOW PROCESSLIST
-
如果一個執行緒的狀態為
THD:KILL_CONNECTION
,Command
列會顯示為Killed
-
28號執行緒只有滿足進入InnoDB的條件後,
session C
的查詢語句將繼續執行-
才有可能判斷到執行緒狀態是否已經變成了
KILL_QUERY
或者KILL_CONNECTION
- 再進入終止邏輯階段
-
才有可能判斷到執行緒狀態是否已經變成了
-
如果一個執行緒的狀態為
KILL無效的情況
-
執行緒沒有執行到判斷執行緒狀態
的邏輯
- innodb_thread_concurrency過小
- 例如IO壓力過大,讀寫IO的函式一直沒有返回,導致不能及時判斷執行緒的狀態
-
終止邏輯耗時較長
,
SHOW PROCESSLIST
顯示為Command=Killed
-
超大事務執行期間被KILL
- 回滾操作需要對事務執行期間生成的所有新資料版本做回收操作 ,耗時很長
-
大查詢回滾
- 查詢過程中生成了較大的臨時檔案 ,恰好此時檔案系統壓力較大
- 刪除臨時檔案需要等待IO資源,導致耗時較長
-
DDL執行到最後階段被KILL
- 需要刪除中間過程的臨時檔案 ,可能受IO資源 影響,耗時比較久
-
超大事務執行期間被KILL
CTRL + C
- 在客戶端的操作只能影響到客戶端的執行緒
- 客戶端與服務端只能通過網路互動 ,因此是不可能直接操作服務端執行緒 的
-
MySQL是停等協議
,在這個執行緒執行的語句還沒有返回的時候,再往該連線發命令是沒有用的
-
實際上,執行
CTRL + C
,MySQL是另起一個連線 ,然後傳送一個KILL QUERY
命令
-
實際上,執行
mysql -A
$ mysql -uroot -Dtest Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A
-
MySQL客戶端預設會提供一個本地庫名和表名補全
的功能,在客戶端連線成功後,會多執行以下操作
-
SHOW DATABASES;
->USE test;
->SHOW TABLES;
- 目的:用於構建一個本地的雜湊表
-
- 當表很多的時候,會表現得慢,但這是客戶端慢 ,而非連線慢 或者服務端慢
mysql –quick
-
MySQL客戶端傳送請求後,接收服務端返回結果的兩種方式
-
使用本地快取
,在本地開闢一片記憶體,先把結果存起來,對應API為
mysql_store_result
-
MySQL客戶端預設行為,即不加引數
--quick
-
MySQL客戶端預設行為,即不加引數
-
不使用本地快取
,讀一個處理一個,對應API為
mysql_use_result
- 如果客戶端本地處理得慢 ,會導致服務端傳送結果被阻塞 ,導致服務端變慢
-
使用本地快取
,在本地開闢一片記憶體,先把結果存起來,對應API為
-
使用
--quick
的效果-
-A
引數,跳過表名自動補全功能 -
mysql_store_result
需要申請本地記憶體 來快取結果- 如果查詢結果太大,可能會影響客戶端本地機器的效能
- 不會把執行命令記錄到本地的命令歷史檔案
-
-
--quick
的目的是為了讓客戶端更快 ,但有可能會降低服務端效能