iT邦幫忙

0

如何中斷 mysql call stored prodedure 之運行?

在 mysql 環境中,假如我有一個 stored procedure 會運行很久,當我下完

call XXX(.....)

之後,可能會跑一、二十分鐘或更長,視參數而定。

我希望在頁面中擺一個按鈕,使用者按下後,可以中斷該 procedure 之運行,這要怎麼設計會比較好?

我知道 KILL PROCESS 可以中斷執行中的作業,但我不知道這一次的 PROCESS ID 是什麼?

要從什麼地方下手呢?

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

0
一級屠豬士
iT邦大師 1 級 ‧ 2020-06-21 09:29:24
最佳解答

看來會是個跑很久的procedure捏.我推測會開cursor,然後迴圈跑跑跑.
建議可以搭配額外兩個table, 一個存放要給這個procedure的command,另一個是存放
這個procedure的status的.
command table 只包含一筆record, 看是要用boolean, 或是 varchar,可以視情況變化.
在procedure中,增加一個 counter, 在loop中,利用除法判斷counter,每N次,就檢查command
table,看是要繼續執行,或是脫離,這樣就能由外部變更command table,來控制procedure的行為.簡單的情境就用boolean,複雜的用varchar,就能有多種command.
至於另外的status table, 就是用來追蹤執行情況,例如啟動時,insert 啟動的資訊,最好是還
有個欄位 default current_timestamp, 這樣會自動有時刻資料.
當作檢查時,也把counter值insert 到status table, 最後脫離時,就insert 脫離的資訊,
也許順帶把counter也放到脫離資訊,或者是就有個欄位放counter值都是可以的.
這樣procedure的情況,我們透過此 status table 就能較好掌握,事後也好追蹤,
也好觀測執行總時間,及階段時間.記得最好要commit.
另外有個 CONNECTION_ID()函數
https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_connection-id

可以視需要,放到status table,看是要獨立欄位,或是轉型別為varchar放到資訊欄,都可以看喜好自行變化.

看更多先前的回應...收起先前的回應...
ckp6250 iT邦好手 1 級 ‧ 2020-06-21 10:14:13 檢舉

感恩殺豬大,
看來,工程浩大,不是我想的三兩下子可以解決,
我試著以此思路來測試一下,

或者,應該設法弄成公用函數,別的耗時的 procedure 也能受用,一勞永逸。

這個就看情況啦,共用有時候會手滑搞錯,我比較建議各自獨立,
簡單清楚,至於要另外做個頁面來看時,就補一個 procedure name
欄位,然後做個view把幾個status table union all 一起就好啦.

ckp6250 iT邦好手 1 級 ‧ 2020-06-22 17:23:48 檢舉

我推測會開cursor,然後迴圈跑跑跑

被您完全猜中,就是一個大cursor,再加上轉個不停的迴圈...

我可比走馬燈,轉無停啊轉無停....

請問殺豬大,若是您大力推薦的 postgresql ,
這個問題有比較簡單的處理方法嗎?

其實用MySQL ,盡量不用cursor,用SQL Command 來處理的,搭配自定義函數以及trigger.也能做到這類的功能.
細節的話,不如我們另外找時間詳談.

ckp6250 iT邦好手 1 級 ‧ 2020-06-22 20:49:15 檢舉

用SQL Command 來處理的,搭配自定義函數以及trigger.也能做到這類的功能.

這個我知道,也的確大量運用,所以我才會說,有一千個函數及trigger,但有些單頭單身要一次整批修改時,同時異動單頭、單身及其它關聯的 table 之數值,這時,有個 cursor 還是比較方便些。

我是不知道 mysql 的 cursor 有什麼潛在風險?為何您主張盡量不要用?願聞其詳!

cursor 沒有不好啊,好多公司,好多重要的系統都是這樣寫的啊.
而且這樣比一些用外部語言,拉資料,跑loop,回寫,效率高多了,
只是現在很多人不會,而且還到處說不要用stored procedure.
其實只要查詢,DB 裡面就會有一個cursor,看你是要慢慢fetch,
或是一次fethch all. 所以cursor 是一定會有的.
我剛才說的是,用stored procedure , open cursor, loop,這招數,很強,但還不是最強的.
一或幾道SQL搞定計算,回寫紀錄,最後效果相同,但是速度更快.這樣更有快感啊.

0
通靈亡
iT邦高手 1 級 ‧ 2020-06-20 20:15:51

參考這個問題:
https://stackoverflow.com/questions/44192418/how-to-find-mysql-process-list-and-to-kill-those-processes

select GROUP_CONCAT(stat SEPARATOR ' ') 
from (select concat('KILL ',id,';') as stat 
   from information_schema.processlist
      where Command='Sleep') as stats;

執行得到KILL <pid>;的語法

看更多先前的回應...收起先前的回應...
ckp6250 iT邦好手 1 級 ‧ 2020-06-20 20:55:53 檢舉

感恩!

但,我在想,

where Command='Sleep'

是否應該改成

where Command='Query'

才對啊?因為我是想中斷【正在運行中】的程序。

通靈亡 iT邦高手 1 級 ‧ 2020-06-20 21:23:27 檢舉

https://dev.mysql.com/doc/refman/5.6/en/thread-commands.html

https://stackoverflow.com/questions/12194241/show-processlist-in-mysql-command-sleep

我剛才查了一下官方文件確認一下
你說的沒錯,要是=Query
Sleep 是等待被終止的process

ckp6250 iT邦好手 1 級 ‧ 2020-06-21 05:15:37 檢舉

感恩!

假如同一時間,有很多個使用者在執行許多相同或不同的 procedure,
那麼,會不會濫殺無辜啊?

where Command='Query';

好像不分青紅皂白?殺無赦?

通靈亡 iT邦高手 1 級 ‧ 2020-06-21 13:25:22 檢舉

雖然屠豬大已提供另一種解法
不過我有想過這個Query得到的一個資訊放一個頁面
在那個頁面終止想要的Query

我記得有個欄位會放執行了什麼Query
如果不會放exec procedureName 這個方法就沒有用了

ckp6250 iT邦好手 1 級 ‧ 2020-06-22 17:19:04 檢舉

在 information_schema.PROCESSLIST 中,
無法查到正在運作中的 procedure Name ,
所以,若要避免誤殺無辜,就只能自己去記錄相關訊息了,
如同殺豬大所提示的方向。

我要發表回答

立即登入回答