在 mysql 環境中,假如我有一個 stored procedure 會運行很久,當我下完
call XXX(.....)
之後,可能會跑一、二十分鐘或更長,視參數而定。
我希望在頁面中擺一個按鈕,使用者按下後,可以中斷該 procedure 之運行,這要怎麼設計會比較好?
我知道 KILL PROCESS 可以中斷執行中的作業,但我不知道這一次的 PROCESS ID 是什麼?
要從什麼地方下手呢?
看來會是個跑很久的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放到資訊欄,都可以看喜好自行變化.
感恩殺豬大,
看來,工程浩大,不是我想的三兩下子可以解決,
我試著以此思路來測試一下,
或者,應該設法弄成公用函數,別的耗時的 procedure 也能受用,一勞永逸。
這個就看情況啦,共用有時候會手滑搞錯,我比較建議各自獨立,
簡單清楚,至於要另外做個頁面來看時,就補一個 procedure name
欄位,然後做個view把幾個status table union all 一起就好啦.
我推測會開cursor,然後迴圈跑跑跑
被您完全猜中,就是一個大cursor,再加上轉個不停的迴圈...
我可比走馬燈,轉無停啊轉無停....
請問殺豬大,若是您大力推薦的 postgresql ,
這個問題有比較簡單的處理方法嗎?
其實用MySQL ,盡量不用cursor,用SQL Command 來處理的,搭配自定義函數以及trigger.也能做到這類的功能.
細節的話,不如我們另外找時間詳談.
用SQL Command 來處理的,搭配自定義函數以及trigger.也能做到這類的功能.
這個我知道,也的確大量運用,所以我才會說,有一千個函數及trigger,但有些單頭單身要一次整批修改時,同時異動單頭、單身及其它關聯的 table 之數值,這時,有個 cursor 還是比較方便些。
我是不知道 mysql 的 cursor 有什麼潛在風險?為何您主張盡量不要用?願聞其詳!
cursor 沒有不好啊,好多公司,好多重要的系統都是這樣寫的啊.
而且這樣比一些用外部語言,拉資料,跑loop,回寫,效率高多了,
只是現在很多人不會,而且還到處說不要用stored procedure.
其實只要查詢,DB 裡面就會有一個cursor,看你是要慢慢fetch,
或是一次fethch all. 所以cursor 是一定會有的.
我剛才說的是,用stored procedure , open cursor, loop,這招數,很強,但還不是最強的.
一或幾道SQL搞定計算,回寫紀錄,最後效果相同,但是速度更快.這樣更有快感啊.
select GROUP_CONCAT(stat SEPARATOR ' ')
from (select concat('KILL ',id,';') as stat
from information_schema.processlist
where Command='Sleep') as stats;
執行得到KILL <pid>;
的語法
感恩!
但,我在想,
where Command='Sleep'
是否應該改成
where Command='Query'
才對啊?因為我是想中斷【正在運行中】的程序。
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