PostgreSQLのexplain analyze中にCTRL+Cでキャンセルすると、途中まで実行されているActual Planの結果は出力されないわけだが、その挙動を、ほんの少し追ってみた件 Tweet
本エントリーは、PostgreSQL Advent Calendar 2023 シリーズ2の Day 22向けエントリーです
今回は、PostgreSQLオンリーで、投げっぱなしだったやつをちょっと掘り下げた時のメモ的なエントリーです。。
以前、
・MySQL 8.0.32 / explain analyze 実行途中でキャンセルできるみたいだけど、キャンセルしたら、Actual Plan、途中まで出るの?
・帰ってきた! 標準はあるにはあるが癖の多いSQL #2 Actual Plan取得中のキャンセルでも癖が出る
というエントリーを書いたのですが、
explain (analyze) 実行中、CTRL+C した時、どのようにハンドングしてるんだろう?
Hookで拾って、extensionで、explain (analyze) でも途中までは結果を書き出せるようにできちゃったりするのだろうか? と。
気になりすぎてしまったのでw、該当ソースコードを追い、象が生息する森の奥地に入ってみることにした。。。。
https://github.com/postgres/postgres
ただ、あてもないのに森林の奥地入り込むのは、迷子になる危険を感じたのでw、ちょっとだけ、生態を調べてみたw
すると、幸運なことに、先人が足を踏み入れた痕跡と思われるメモ見つけることができた。
PostgreSQLのシグナル周り
https://qiita.com/KazuyaTomita/items/6feb708d73190032dfed
ふむふむ、なんとなくわかった気持ちになる。。(理解したとは言ってない)
PostgreSQLのActual Plan取得のログ。
見ての通り、PostgreSQLは、explain (analyze)実行中にCTRL+Cでキャンセルすると、シンプルなキャンセルメッセージを返すだけ。
(MySQL/Oracleでは、キャンセルされるまでのActual Planを返してくれる。冒頭のリンク参照)
この表示されているメッセージは手がかりになりそうだなぁ。。。。
perftestdb=> explain (analyze, buffers, verbose)
WITH RECURSIVE gen_nums(v)
AS
(
SELECT 1
UNION ALL
SELECT v + 1
FROM
gen_nums
WHERE v + 1 <= 100000000
)
SELECT v from gen_nums;
^Cキャンセル要求を送信しました
ERROR: canceling statement due to user request
perftestdb=>
シグナル周りのハンドリング部分のコードを追って、このメッセージを出力しているところを特定すると良さげな気がしますよね。
ただ、explain を実行している箇所とは違いそうではある。。。ざっくり目だが。
postgres.cのPostgresMain()に以下の文がありますな〜
postgres.c
pqsignal(SIGINT, StatementCancelHandler); /* cancel current query */
そして、至る所で、 CHECK_FOR_INTERRUPTS ()マクロが呼ばれてます〜〜。
CHECK_FOR_INTERRUPTS()マクロで、呼ばれているのが、 ProcessInterrupts() ですね。
miscadmin.h
/* Service interrupt, if one is pending and it's safe to service it now */
#define CHECK_FOR_INTERRUPTS() \
do { \
if (INTERRUPTS_PENDING_CONDITION()) \
ProcessInterrupts(); \
} while(0)
ProcessInterrupts()をみると、以下に見覚えのあるエラーメッセージ "canceling statement due to user request"を出力している箇所を発見。
postgres.c
/*
* If we are reading a command from the client, just ignore the cancel
* request --- sending an extra error message won't accomplish
* anything. Otherwise, go ahead and throw the error.
*/
if (!DoingCommandRead)
{
LockErrorCleanup();
ereport(ERROR,
(errcode(ERRCODE_QUERY_CANCELED),
errmsg("canceling statement due to user request")));
}
explain (analyze)に関わりそうな以下のコードでは、CHECK_FOR_INTERRUPTSはないのだけど、executer配下のコードには沢山ある。。。
explain.c
execMain.c
... extensionでなんとか、、というのは雰囲気的に難しそうな。。。
explain (actual plan取得含む)実行中に CTRL+C キャンセルすると、
postgres.c の PostgresMain() -> CHECK_FOR_INTERRUPTS() -> ProcessInterrupts() -> ereport() -> errmsg("canceling statement due to user request") を出力して実行キャンセル
と言う流れっぽい。斜め読みした限りでは。
ぱっと見だが、
errmsg("canceling statement due to user request")の前に、
1. commandが実行されているか
2. 1.であれば、commandは、explain かつ analyzeか?
3. 2.であれば、explain analyzeのキャンセルされる前に取得されたActual Planの結果を出力
みたいなことを、ProcessInterrupts()内でやらないと難しそうだよなぁ〜と。extensionでやれそうな感じにも見えないし。。。
一旦、そっとGitHubを開いていたブラウザのタブを閉じたww
と言うことで、冬の夜長に、PostgreSQLのコードをちょっと追ってみた話はここまで。
PostgreSQL Advent Calendar 2023 ですがw 恒例?の、Oracle Pipelined Table Function で Christmas ASCII Art(クロスポストに続き2回目)
関連エントリー
・MySQL 8.0.32 / explain analyze 実行途中でキャンセルできるみたいだけど、キャンセルしたら、Actual Plan、途中まで出るの?
・帰ってきた! 標準はあるにはあるが癖の多いSQL #2 Actual Plan取得中のキャンセルでも癖が出る
| 固定リンク | 0


コメント