© 2024 NTT DATA Group Corporation
© 2024 NTT DATA Group Corporation
第49回 PostgreSQLアンカンファレンス@東京
PostgreSQL17対応版
EXPLAINオプションについて
2024年10月12日(土)
NTTデータグループ 池田 真洋
© 2024 NTT DATA Group Corporation 2
自己紹介
池田真洋(いけだまさひろ)
• PostgreSQLに関する技術検証や技術支援などを実施
• PostgreSQL歴は約4年で、初めて触ったバージョンはv13
• PostgreSQLの好きな機能や仕組みは、EXPLAINと待機イベント
© 2024 NTT DATA Group Corporation 3
本講演について
講演資料は、後日、NTTデータグループのSlideShareのアカウント上で公開予定です。
• https://www.slideshare.net/nttdata-tech
本資料での動作確認には、PostgreSQL 17.0を利用しています。
© 2024 NTT DATA Group Corporation 4
EXPLAINコマンドについて
実行計画を出力するコマンドで、クエリ性能の最適化やトラブル解析などで利用される、重要なコマンドの1つ
EXPLAINコマンドが活用される場面はたくさん
• クエリが急に遅くなった...
• 試験環境では高速だったのに、本番環境では性能が劣化してしまった...
• 定期的にクエリが劣化するタイミングがある...
EXPLAINコマンドの実行例
psql=# EXPLAIN (COSTS off)
SELECT SUM(bbalance) FROM pgbench_accounts a JOIN pgbench_branches b ON a.bid = b.bid WHERE a.aid = 10;
QUERY PLAN
--------------------------------------------------------------------------
Aggregate
-> Nested Loop
Join Filter: (b.bid = a.bid)
-> Index Scan using pgbench_accounts_pkey on pgbench_accounts a
Index Cond: (aid = 10)
-> Seq Scan on pgbench_branches b
(6 rows)
© 2024 NTT DATA Group Corporation 5
EXPLAINコマンドの改善について
EXPLAINコマンド自体は、初期から存在しているが、最近のバージョンでも様々な改善が行われている
• 新しい処理(例えば、パラレルクエリやMemoize(*1)など)が追加されたときなど、処理固有の情報が出力されるようになる
• 特定の処理に関連しないが、新たな情報を出力するオプションが追加される ⇒ 今回こちらを紹介
新しい処理が追加されたとき
(*1) Memoizeを理解するには、過去のアンカンファレンスでの発表内容がおすすめです
Memoizeの仕組み(第41回PostgreSQLアンカンファレンス@オンライン 発表資料) | PPT (slideshare.net)
-- v14から追加された仕組みである”Memoize(Nested Loop Joinの高速化の仕組み)”が利用される実行計画
=# EXPLAIN (COSTS off) SELECT * FROM t1, t2 WHERE t1.c1 = t2.c1;
QUERY PLAN
----------------------------------------------
Nested Loop
-> Seq Scan on t1
-> Memoize ← 新しい処理が追加されるとEXPLAINでも対応する情報が出力される
Cache Key: t1.c1
Cache Mode: logical
-> Index Scan using t2_c1_idx on t2
Index Cond: (c1 = t1.c1)
(7 rows)
© 2024 NTT DATA Group Corporation 6
EXPLAINコマンドのオプション改善について
v17では12個のオプションを指定することができ、最近でも改善が続けられていることが分かる
• 2023年にEOLを迎えたv11と比較しても、5個のオプションが追加されている。
• v12よりも後に追加されたオプションは、デフォルトoffであることもあり、知らない方も多そうなので詳細は後述
EXPLAINコマンドで指定可能なオプション
# オプション 説明 デフォルト 追加バージョン(*1)
1 ANALYZE コマンドを実行し、実行時間などを出力する off ~v11
2 VERBOSE スキーマ修飾などの追加情報も出力する off ~v11
3 COSTS コスト情報や推定行数などの情報を出力する on ~v11
4 BUFFERS バッファの使用状況に関する情報を出力する off ~v11
5 TIMING スタートアップ時間やノード実行時間に関する情報を出力する on ~v11
6 SUMMARY 実行時間の合計などの要約情報を出力する on (ANALYZE指定時)
off (ANALYZE未指定時)
~v11
7 FORMAT 出力形式を指定する. TEXT, XML, JSON, YAMLが指定可能 TEXT ~v11
8 SETTINGS 設定パラメータに関する情報を出力する off v12
9 WAL 生成されたWAL情報を出力する off v13
10 GENERIC_PLAN 独自計画ではなく、汎用的な計画での実行計画を出力する off v16
11 SERIALIZE 結果をシリアライズするコストを出力する。NONE,TEXT, BINARYが指定可能 NONE v17
12 MEMORY 実行計画時のメモリ使用量を出力する off v17
(*1) 2023年にEOLを迎えたv11以降に追加されたものだけを記載
次ページ
から詳細
© 2024 NTT DATA Group Corporation 7
SETTINGSオプション(v12~)
実行計画に影響を与えるパラメータ値(デフォルト値と異なる値のみ)を出力するオプション
• 背景:実行計画を生成したパラメータ条件も合わせて管理できるように追加された
• 想定ユースケース:パラメータの影響を実行計画に含めて管理したい場合に利用できる
➢ 例えば、「クエリ最適化のため、様々なパラメータで、実行計画を確認したが、記録し忘れた...」といったことを防げる
-- SETTINGSオプションを付与したときの実行例
psql=# EXPLAIN (COSTS off, SETTINGS on)
SELECT * FROM pgbench_accounts a JOIN pgbench_branches b ON a.bid = b.bid WHERE a.aid = 101;
QUERY PLAN
--------------------------------------------------------------------------------------
Nested Loop
Join Filter: (b.bid = a.bid)
-> Index Scan using pgbench_accounts_pkey on pgbench_accounts a
Index Cond: (aid = 101)
-> Seq Scan on pgbench_branches b
Settings: effective_cache_size = ‘3933MB’, work_mem = ‘7MB’, enable_hashjoin = ‘off’ ← デフォルトと異なるパラメータ値が出力
(6 rows)
© 2024 NTT DATA Group Corporation 8
SETTINGSオプション(v12~)
例えば、hash joinのパラメータチューニングを実施するときの例
-- チューニング前:work_memが小さすぎて、hash joinのときの “Batch数” が多い
psql=# EXPLAIN (COSTS off, ANALYZE on, SETTINGS on)
SELECT * FROM pgbench_accounts a1 JOIN pgbench_accounts a2 ON a1.aid = a2.aid - 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------
Hash Join (actual time=474.388..1799.584 rows=999999 loops=1)
Hash Cond: ((a2.aid - 1) = a1.aid)
-> Seq Scan on pgbench_accounts a2 (actual time=0.007..96.662 rows=1000000 loops=1)
-> Hash (actual time=453.346..453.347 rows=1000000 loops=1)
Buckets: 1024 Batches: 2048 Memory Usage: 71kB
-> Seq Scan on pgbench_accounts a1 (actual time=0.002..103.462 rows=1000000 loops=1)
Settings: work_mem = '64kB', max_parallel_workers = '0'
Planning Time: 0.106 ms
Execution Time: 1826.629 ms
(9 rows)
-- チューニング後:work_memを増やすと “Batch数” が少なくなり、実行時間も
QUERY PLAN
-----------------------------------------------------------------------------------------------
Hash Join (actual time=408.273..1130.962 rows=999999 loops=1)
Hash Cond: ((a2.aid - 1) = a1.aid)
-> Seq Scan on pgbench_accounts a2 (actual time=0.018..107.200 rows=1000000 loops=1)
-> Hash (actual time=408.004..408.006 rows=1000000 loops=1)
Buckets: 1048576 Batches: 1 Memory Usage: 134169kB
-> Seq Scan on pgbench_accounts a1 (actual time=0.006..102.828 rows=1000000 loops=1)
Settings: work_mem = ‘1GB’, max_parallel_workers = ‘0’ ← work_memの値が実行計画に含まれるため、記録忘れや、確認時のミスなどを防げる
Planning Time: 0.220 ms
Execution Time: 1175.805 ms
(9 rows)
© 2024 NTT DATA Group Corporation 9
WALオプション(v13~)
生成されたWALレコードに関する情報を出力するオプション
• 背景:クエリが生成するWALに関する情報をクエリごとに確認できるように追加された
• 想定ユースケース:WAL書き込みがボトルネックになっている場合に問題になっているクエリ特定などに利用できる
➢ EXPLAINだけでなく、pg_stat_statementsでも、クエリごとのWAL生成に関する統計情報が確認できる(v13~)
➢ 「あるクエリ条件でのWAL生成量を見たい」といったケースでは、EXPLAINの方が確認しやすい
-- WALオプションを付与したときの実行例
psql=# EXPLAIN (SUMMARY off, COSTS off, ANALYZE on, WAL on) ← 実際の出力量を確認するため、ANALYZEオプションも必要
UPDATE pgbench_accounts SET abalance = abalance + 100 WHERE aid = 101;
QUERY PLAN
------------------------------------------------------------------------------------------------------------
Update on pgbench_accounts (actual time=0.110..0.110 rows=0 loops=1)
WAL: records=1 fpi=1 bytes=5237 ← 生成されたWALレコード数、WALフルページイメージ数、WALバイト数が出力される
-> Index Scan using pgbench_accounts_pkey on pgbench_accounts (actual time=0.037..0.039 rows=1 loops=1)
Index Cond: (aid = 101)
(4 rows)
© 2024 NTT DATA Group Corporation 10
GENERIC_PLANオプション(v16~)
「汎用的な計画」での実行計画を作成することを指定するためのオプション。未指定の場合は「独自計画」が生成される
• 背景:汎用的な計画の実行計画を確認しようとすると、少し手間がかかっていたので簡単に確認できるように追加された
• 想定ユースケース:「汎用的な計画」と「独自計画」での性能差が疑われる場合の切り分けなどで利用できる
➢ 例えば、よくあるトラブル事例としては、PREPARE文を利用しているクエリが、6回目以降で性能劣化する
(独自計画から、汎用的な計画に切り替わったことで、処理コストが増加してしまったというケース)
(参考)「汎用的な計画」と「独自計画」とは
• PREPARE文を利用するときに生成される計画のこと。引数の条件などが同じでも2種類の計画が生成される可能性がある
-- PREPARE文でクエリをキャッシュ
-- (パラメータとして指定できる)
=# PREPARE pfunc (int) AS
SELECT * FROM users u
WHERE u.id=$1;
-- クエリを実行
=# EXECUTE pfunc(101);
PostgreSQLサーバ
Parser(※)
Analyzer(※)
Planner
Executor
※PREPARE文の場合
構文解析をスキップできる
クエリ処理
生成される可能性がある実行計画は2種類
デフォルト(plan_cache_modeパラメータ=auto)の場合
1. 最初の5回は、①独自計画が採用される
2. 6回目で、①独自計画(5回分)と②汎用計画のコストを比較して、その後の計画を決定
3. 6回目からは、決まった計画だけが利用される
① 独自計画:実行計画は最適. ただ、パラメータ値ごとに生成するオーバヘッドあり
SELECT * FROM users u WHERE u.id = 101; ← パラメータ値を考慮した計画
② 汎用的な計画:実行計画の生成コストなし. ただ、パラメータ値によっては最適でないかも
SELECT * FROM users u WHERE u.id = $1; ← パラメータ値を考慮しない計画
© 2024 NTT DATA Group Corporation 11
GENERIC_PLANオプション(v16~)
-- 独自計画(カスタムプラン)
psql=# EXPLAIN (GENERIC_PLAN off) ← デフォルト
SELECT SUM(bid) FROM pgbench_accounts WHERE aid < 100; ← デフォルトでは独自計画のため、実際の値を指定したときの実行計画が生成される
QUERY PLAN
-------------------------------------------------------------------------------------------------------
Aggregate (cost=11.47..11.48 rows=1 width=8)
-> Index Scan using pgbench_accounts_pkey on pgbench_accounts (cost=0.42..11.21 rows=102 width=4)
Index Cond: (aid < 100)
(3 rows)
-- 汎用的な計画(ジェネリックプラン)
psql=# EXPLAIN (GENERIC_PLAN on)
SELECT SUM(bid) FROM pgbench_accounts WHERE aid < $1; ← パラメータとして指定できるように。汎用的な計画が生成される
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------- -----
Finalize Aggregate (cost=14364.75..14364.76 rows=1 width=8)
-> Gather (cost=14364.53..14364.74 rows=2 width=8)
Workers Planned: 2 ← この例だと、汎用的な計画では、データ量が多くなることが想定されるため、パラレルクエリが採用される
-> Partial Aggregate (cost=13364.53..13364.54 rows=1 width=8)
-> Parallel Index Scan using pgbench_accounts_pkey on pgbench_accounts (cost=0.42..13017.31 rows=138889 width=4)
Index Cond: (aid < $1)
(6 rows)
「独自計画」 「汎用的な計画」の実行計画の出力例
© 2024 NTT DATA Group Corporation 12
SERIALIZEオプション(v17)
クエリ結果をクライアントに応答する前のシリアライズ時間、シリアライズ後のサイズを出力するオプション
• 背景: 処理時間の大部分をシリアライズ時間が占めるケースがあり、解析をしやすくするために追加された
➢ 特定のデータ型やTOASTされた結果が含まれる場合など、シリアライズに時間がかかりやすい
• 想定ユースケース: クエリ実行時間と比較して、クライアントへの応答に時間がかかる場合の切り分けとして利用できる
➢ シリアライズが遅い? or クライアントへのNW通信が遅い? など
-- SERIALIZEオプションを付与した時の実行例
psql=# EXPLAIN (ANALYZE, COSTS off, SERIALIZE BINARY) ← TEXTも指定可能
SELECT * FROM pgbench_accounts;
QUERY PLAN
--------------------------------------------------------------------------------
Seq Scan on pgbench_accounts (actual time=0.027..219.814 rows=1000000 loops=1)
Planning Time: 0.089 ms
Serialization: time=1059.206 ms output=111329kB format=binary ← 時間、出力サイズ、出力フォーマット
Execution Time: 1369.677 ms ← このケースだと実行時間の約80%がシリアライズ時間
(4 rows)
© 2024 NTT DATA Group Corporation 13
MEMORYオプション(v17)
実行計画を作成するときに使用されたメモリ消費量を出力するオプション
• 背景: 実行計画を作成時にメモリ消費量が増加するケース(*1)が報告され、簡単に確認できるように追加された
➢ この時はパーティション・ワイズ結合を利用すると、実行計画を作成するときに1GB以上のメモリ消費が発生していたとの報告
• 想定ユースケース: スワップ発生により性能劣化が発生しているといった事象の解析に利用できる可能性がある
-- MEMORYオプションを付与した時の実行例
psql=# EXPLAIN (MEMORY)
SELECT SUM(bid) FROM pgbench_accounts WHERE aid < 100;
QUERY PLAN
------------------------------------------------------------------------------------------------------
Aggregate (cost=11.35..11.36 rows=1 width=8)
-> Index Scan using pgbench_accounts_pkey on pgbench_accounts (cost=0.42..11.11 rows=96 width=4)
Index Cond: (aid < 100)
Planning: ← 実行計画を作成する時のメモリ消費に関する情報
Memory: used=15kB allocated=32kB ← usedは実際に消費されたメモリ量、allocatedは確保されたメモリ量
(5 rows)
(*1) https://www.postgresql.org/message-id/CAExHW5tHqEf3ASVqvFFcghYGPfpy7o3xnvhHwBGbJFMRH8KjNw@mail.gmail.com
© 2024 NTT DATA Group Corporation 14
まとめ
本講演では、EXPLAINコマンドでサポートされているオプションについて紹介しました。
よく利用されるコマンドですが、最近のバージョン(v12以降)でもオプションが追加されており、様々な改善が行われています。
今回の講演で新しく知ったオプションなどがあれば、ぜひ実際のシステム開発や運用でも利用してみてください。
最近追加されたオプションは、デフォルトでは無効化(off)されているので、明示的に指定(on)して試してみてください
# オプション 説明 デフォルト 追加バージョン
1 ANALYZE コマンドを実行し、実行時間などを出力する off ~v11
2 VERBOSE スキーマ修飾などの追加情報も出力する off ~v11
3 COSTS コスト情報や推定行数などの情報を出力する on ~v11
4 BUFFERS バッファの使用状況に関する情報を出力する off ~v11
5 TIMING スタートアップ時間やノード実行時間に関する情報を出力する on ~v11
6 SUMMARY 実行時間の合計などの要約情報を出力する on (ANALYZE指定時)
off (ANALYZE未指定時)
~v11
7 FORMAT 出力形式を指定する. TEXT, XML, JSON, YAMLが指定可能 TEXT ~v11
8 SETTINGS 設定パラメータに関する情報を出力する off v12
9 WAL 生成されたWAL情報を出力する off v13
10 GENERIC_PLAN 汎用的な計画での実行計画を出力する off v16
11 SERIALIZE 結果をシリアライズするコストを出力する。NONE,TEXT, BINARYが指定可能 NONE v17
12 MEMORY 実行計画時のメモリ使用量を出力する off v17

PostgreSQL17対応版 EXPLAINオプションについて (第49回PostgreSQLアンカンファレンス@東京 発表資料)

  • 1.
    © 2024 NTTDATA Group Corporation © 2024 NTT DATA Group Corporation 第49回 PostgreSQLアンカンファレンス@東京 PostgreSQL17対応版 EXPLAINオプションについて 2024年10月12日(土) NTTデータグループ 池田 真洋
  • 2.
    © 2024 NTTDATA Group Corporation 2 自己紹介 池田真洋(いけだまさひろ) • PostgreSQLに関する技術検証や技術支援などを実施 • PostgreSQL歴は約4年で、初めて触ったバージョンはv13 • PostgreSQLの好きな機能や仕組みは、EXPLAINと待機イベント
  • 3.
    © 2024 NTTDATA Group Corporation 3 本講演について 講演資料は、後日、NTTデータグループのSlideShareのアカウント上で公開予定です。 • https://www.slideshare.net/nttdata-tech 本資料での動作確認には、PostgreSQL 17.0を利用しています。
  • 4.
    © 2024 NTTDATA Group Corporation 4 EXPLAINコマンドについて 実行計画を出力するコマンドで、クエリ性能の最適化やトラブル解析などで利用される、重要なコマンドの1つ EXPLAINコマンドが活用される場面はたくさん • クエリが急に遅くなった... • 試験環境では高速だったのに、本番環境では性能が劣化してしまった... • 定期的にクエリが劣化するタイミングがある... EXPLAINコマンドの実行例 psql=# EXPLAIN (COSTS off) SELECT SUM(bbalance) FROM pgbench_accounts a JOIN pgbench_branches b ON a.bid = b.bid WHERE a.aid = 10; QUERY PLAN -------------------------------------------------------------------------- Aggregate -> Nested Loop Join Filter: (b.bid = a.bid) -> Index Scan using pgbench_accounts_pkey on pgbench_accounts a Index Cond: (aid = 10) -> Seq Scan on pgbench_branches b (6 rows)
  • 5.
    © 2024 NTTDATA Group Corporation 5 EXPLAINコマンドの改善について EXPLAINコマンド自体は、初期から存在しているが、最近のバージョンでも様々な改善が行われている • 新しい処理(例えば、パラレルクエリやMemoize(*1)など)が追加されたときなど、処理固有の情報が出力されるようになる • 特定の処理に関連しないが、新たな情報を出力するオプションが追加される ⇒ 今回こちらを紹介 新しい処理が追加されたとき (*1) Memoizeを理解するには、過去のアンカンファレンスでの発表内容がおすすめです Memoizeの仕組み(第41回PostgreSQLアンカンファレンス@オンライン 発表資料) | PPT (slideshare.net) -- v14から追加された仕組みである”Memoize(Nested Loop Joinの高速化の仕組み)”が利用される実行計画 =# EXPLAIN (COSTS off) SELECT * FROM t1, t2 WHERE t1.c1 = t2.c1; QUERY PLAN ---------------------------------------------- Nested Loop -> Seq Scan on t1 -> Memoize ← 新しい処理が追加されるとEXPLAINでも対応する情報が出力される Cache Key: t1.c1 Cache Mode: logical -> Index Scan using t2_c1_idx on t2 Index Cond: (c1 = t1.c1) (7 rows)
  • 6.
    © 2024 NTTDATA Group Corporation 6 EXPLAINコマンドのオプション改善について v17では12個のオプションを指定することができ、最近でも改善が続けられていることが分かる • 2023年にEOLを迎えたv11と比較しても、5個のオプションが追加されている。 • v12よりも後に追加されたオプションは、デフォルトoffであることもあり、知らない方も多そうなので詳細は後述 EXPLAINコマンドで指定可能なオプション # オプション 説明 デフォルト 追加バージョン(*1) 1 ANALYZE コマンドを実行し、実行時間などを出力する off ~v11 2 VERBOSE スキーマ修飾などの追加情報も出力する off ~v11 3 COSTS コスト情報や推定行数などの情報を出力する on ~v11 4 BUFFERS バッファの使用状況に関する情報を出力する off ~v11 5 TIMING スタートアップ時間やノード実行時間に関する情報を出力する on ~v11 6 SUMMARY 実行時間の合計などの要約情報を出力する on (ANALYZE指定時) off (ANALYZE未指定時) ~v11 7 FORMAT 出力形式を指定する. TEXT, XML, JSON, YAMLが指定可能 TEXT ~v11 8 SETTINGS 設定パラメータに関する情報を出力する off v12 9 WAL 生成されたWAL情報を出力する off v13 10 GENERIC_PLAN 独自計画ではなく、汎用的な計画での実行計画を出力する off v16 11 SERIALIZE 結果をシリアライズするコストを出力する。NONE,TEXT, BINARYが指定可能 NONE v17 12 MEMORY 実行計画時のメモリ使用量を出力する off v17 (*1) 2023年にEOLを迎えたv11以降に追加されたものだけを記載 次ページ から詳細
  • 7.
    © 2024 NTTDATA Group Corporation 7 SETTINGSオプション(v12~) 実行計画に影響を与えるパラメータ値(デフォルト値と異なる値のみ)を出力するオプション • 背景:実行計画を生成したパラメータ条件も合わせて管理できるように追加された • 想定ユースケース:パラメータの影響を実行計画に含めて管理したい場合に利用できる ➢ 例えば、「クエリ最適化のため、様々なパラメータで、実行計画を確認したが、記録し忘れた...」といったことを防げる -- SETTINGSオプションを付与したときの実行例 psql=# EXPLAIN (COSTS off, SETTINGS on) SELECT * FROM pgbench_accounts a JOIN pgbench_branches b ON a.bid = b.bid WHERE a.aid = 101; QUERY PLAN -------------------------------------------------------------------------------------- Nested Loop Join Filter: (b.bid = a.bid) -> Index Scan using pgbench_accounts_pkey on pgbench_accounts a Index Cond: (aid = 101) -> Seq Scan on pgbench_branches b Settings: effective_cache_size = ‘3933MB’, work_mem = ‘7MB’, enable_hashjoin = ‘off’ ← デフォルトと異なるパラメータ値が出力 (6 rows)
  • 8.
    © 2024 NTTDATA Group Corporation 8 SETTINGSオプション(v12~) 例えば、hash joinのパラメータチューニングを実施するときの例 -- チューニング前:work_memが小さすぎて、hash joinのときの “Batch数” が多い psql=# EXPLAIN (COSTS off, ANALYZE on, SETTINGS on) SELECT * FROM pgbench_accounts a1 JOIN pgbench_accounts a2 ON a1.aid = a2.aid - 1; QUERY PLAN ----------------------------------------------------------------------------------------------- Hash Join (actual time=474.388..1799.584 rows=999999 loops=1) Hash Cond: ((a2.aid - 1) = a1.aid) -> Seq Scan on pgbench_accounts a2 (actual time=0.007..96.662 rows=1000000 loops=1) -> Hash (actual time=453.346..453.347 rows=1000000 loops=1) Buckets: 1024 Batches: 2048 Memory Usage: 71kB -> Seq Scan on pgbench_accounts a1 (actual time=0.002..103.462 rows=1000000 loops=1) Settings: work_mem = '64kB', max_parallel_workers = '0' Planning Time: 0.106 ms Execution Time: 1826.629 ms (9 rows) -- チューニング後:work_memを増やすと “Batch数” が少なくなり、実行時間も QUERY PLAN ----------------------------------------------------------------------------------------------- Hash Join (actual time=408.273..1130.962 rows=999999 loops=1) Hash Cond: ((a2.aid - 1) = a1.aid) -> Seq Scan on pgbench_accounts a2 (actual time=0.018..107.200 rows=1000000 loops=1) -> Hash (actual time=408.004..408.006 rows=1000000 loops=1) Buckets: 1048576 Batches: 1 Memory Usage: 134169kB -> Seq Scan on pgbench_accounts a1 (actual time=0.006..102.828 rows=1000000 loops=1) Settings: work_mem = ‘1GB’, max_parallel_workers = ‘0’ ← work_memの値が実行計画に含まれるため、記録忘れや、確認時のミスなどを防げる Planning Time: 0.220 ms Execution Time: 1175.805 ms (9 rows)
  • 9.
    © 2024 NTTDATA Group Corporation 9 WALオプション(v13~) 生成されたWALレコードに関する情報を出力するオプション • 背景:クエリが生成するWALに関する情報をクエリごとに確認できるように追加された • 想定ユースケース:WAL書き込みがボトルネックになっている場合に問題になっているクエリ特定などに利用できる ➢ EXPLAINだけでなく、pg_stat_statementsでも、クエリごとのWAL生成に関する統計情報が確認できる(v13~) ➢ 「あるクエリ条件でのWAL生成量を見たい」といったケースでは、EXPLAINの方が確認しやすい -- WALオプションを付与したときの実行例 psql=# EXPLAIN (SUMMARY off, COSTS off, ANALYZE on, WAL on) ← 実際の出力量を確認するため、ANALYZEオプションも必要 UPDATE pgbench_accounts SET abalance = abalance + 100 WHERE aid = 101; QUERY PLAN ------------------------------------------------------------------------------------------------------------ Update on pgbench_accounts (actual time=0.110..0.110 rows=0 loops=1) WAL: records=1 fpi=1 bytes=5237 ← 生成されたWALレコード数、WALフルページイメージ数、WALバイト数が出力される -> Index Scan using pgbench_accounts_pkey on pgbench_accounts (actual time=0.037..0.039 rows=1 loops=1) Index Cond: (aid = 101) (4 rows)
  • 10.
    © 2024 NTTDATA Group Corporation 10 GENERIC_PLANオプション(v16~) 「汎用的な計画」での実行計画を作成することを指定するためのオプション。未指定の場合は「独自計画」が生成される • 背景:汎用的な計画の実行計画を確認しようとすると、少し手間がかかっていたので簡単に確認できるように追加された • 想定ユースケース:「汎用的な計画」と「独自計画」での性能差が疑われる場合の切り分けなどで利用できる ➢ 例えば、よくあるトラブル事例としては、PREPARE文を利用しているクエリが、6回目以降で性能劣化する (独自計画から、汎用的な計画に切り替わったことで、処理コストが増加してしまったというケース) (参考)「汎用的な計画」と「独自計画」とは • PREPARE文を利用するときに生成される計画のこと。引数の条件などが同じでも2種類の計画が生成される可能性がある -- PREPARE文でクエリをキャッシュ -- (パラメータとして指定できる) =# PREPARE pfunc (int) AS SELECT * FROM users u WHERE u.id=$1; -- クエリを実行 =# EXECUTE pfunc(101); PostgreSQLサーバ Parser(※) Analyzer(※) Planner Executor ※PREPARE文の場合 構文解析をスキップできる クエリ処理 生成される可能性がある実行計画は2種類 デフォルト(plan_cache_modeパラメータ=auto)の場合 1. 最初の5回は、①独自計画が採用される 2. 6回目で、①独自計画(5回分)と②汎用計画のコストを比較して、その後の計画を決定 3. 6回目からは、決まった計画だけが利用される ① 独自計画:実行計画は最適. ただ、パラメータ値ごとに生成するオーバヘッドあり SELECT * FROM users u WHERE u.id = 101; ← パラメータ値を考慮した計画 ② 汎用的な計画:実行計画の生成コストなし. ただ、パラメータ値によっては最適でないかも SELECT * FROM users u WHERE u.id = $1; ← パラメータ値を考慮しない計画
  • 11.
    © 2024 NTTDATA Group Corporation 11 GENERIC_PLANオプション(v16~) -- 独自計画(カスタムプラン) psql=# EXPLAIN (GENERIC_PLAN off) ← デフォルト SELECT SUM(bid) FROM pgbench_accounts WHERE aid < 100; ← デフォルトでは独自計画のため、実際の値を指定したときの実行計画が生成される QUERY PLAN ------------------------------------------------------------------------------------------------------- Aggregate (cost=11.47..11.48 rows=1 width=8) -> Index Scan using pgbench_accounts_pkey on pgbench_accounts (cost=0.42..11.21 rows=102 width=4) Index Cond: (aid < 100) (3 rows) -- 汎用的な計画(ジェネリックプラン) psql=# EXPLAIN (GENERIC_PLAN on) SELECT SUM(bid) FROM pgbench_accounts WHERE aid < $1; ← パラメータとして指定できるように。汎用的な計画が生成される QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- ----- Finalize Aggregate (cost=14364.75..14364.76 rows=1 width=8) -> Gather (cost=14364.53..14364.74 rows=2 width=8) Workers Planned: 2 ← この例だと、汎用的な計画では、データ量が多くなることが想定されるため、パラレルクエリが採用される -> Partial Aggregate (cost=13364.53..13364.54 rows=1 width=8) -> Parallel Index Scan using pgbench_accounts_pkey on pgbench_accounts (cost=0.42..13017.31 rows=138889 width=4) Index Cond: (aid < $1) (6 rows) 「独自計画」 「汎用的な計画」の実行計画の出力例
  • 12.
    © 2024 NTTDATA Group Corporation 12 SERIALIZEオプション(v17) クエリ結果をクライアントに応答する前のシリアライズ時間、シリアライズ後のサイズを出力するオプション • 背景: 処理時間の大部分をシリアライズ時間が占めるケースがあり、解析をしやすくするために追加された ➢ 特定のデータ型やTOASTされた結果が含まれる場合など、シリアライズに時間がかかりやすい • 想定ユースケース: クエリ実行時間と比較して、クライアントへの応答に時間がかかる場合の切り分けとして利用できる ➢ シリアライズが遅い? or クライアントへのNW通信が遅い? など -- SERIALIZEオプションを付与した時の実行例 psql=# EXPLAIN (ANALYZE, COSTS off, SERIALIZE BINARY) ← TEXTも指定可能 SELECT * FROM pgbench_accounts; QUERY PLAN -------------------------------------------------------------------------------- Seq Scan on pgbench_accounts (actual time=0.027..219.814 rows=1000000 loops=1) Planning Time: 0.089 ms Serialization: time=1059.206 ms output=111329kB format=binary ← 時間、出力サイズ、出力フォーマット Execution Time: 1369.677 ms ← このケースだと実行時間の約80%がシリアライズ時間 (4 rows)
  • 13.
    © 2024 NTTDATA Group Corporation 13 MEMORYオプション(v17) 実行計画を作成するときに使用されたメモリ消費量を出力するオプション • 背景: 実行計画を作成時にメモリ消費量が増加するケース(*1)が報告され、簡単に確認できるように追加された ➢ この時はパーティション・ワイズ結合を利用すると、実行計画を作成するときに1GB以上のメモリ消費が発生していたとの報告 • 想定ユースケース: スワップ発生により性能劣化が発生しているといった事象の解析に利用できる可能性がある -- MEMORYオプションを付与した時の実行例 psql=# EXPLAIN (MEMORY) SELECT SUM(bid) FROM pgbench_accounts WHERE aid < 100; QUERY PLAN ------------------------------------------------------------------------------------------------------ Aggregate (cost=11.35..11.36 rows=1 width=8) -> Index Scan using pgbench_accounts_pkey on pgbench_accounts (cost=0.42..11.11 rows=96 width=4) Index Cond: (aid < 100) Planning: ← 実行計画を作成する時のメモリ消費に関する情報 Memory: used=15kB allocated=32kB ← usedは実際に消費されたメモリ量、allocatedは確保されたメモリ量 (5 rows) (*1) https://www.postgresql.org/message-id/CAExHW5tHqEf3ASVqvFFcghYGPfpy7o3xnvhHwBGbJFMRH8KjNw@mail.gmail.com
  • 14.
    © 2024 NTTDATA Group Corporation 14 まとめ 本講演では、EXPLAINコマンドでサポートされているオプションについて紹介しました。 よく利用されるコマンドですが、最近のバージョン(v12以降)でもオプションが追加されており、様々な改善が行われています。 今回の講演で新しく知ったオプションなどがあれば、ぜひ実際のシステム開発や運用でも利用してみてください。 最近追加されたオプションは、デフォルトでは無効化(off)されているので、明示的に指定(on)して試してみてください # オプション 説明 デフォルト 追加バージョン 1 ANALYZE コマンドを実行し、実行時間などを出力する off ~v11 2 VERBOSE スキーマ修飾などの追加情報も出力する off ~v11 3 COSTS コスト情報や推定行数などの情報を出力する on ~v11 4 BUFFERS バッファの使用状況に関する情報を出力する off ~v11 5 TIMING スタートアップ時間やノード実行時間に関する情報を出力する on ~v11 6 SUMMARY 実行時間の合計などの要約情報を出力する on (ANALYZE指定時) off (ANALYZE未指定時) ~v11 7 FORMAT 出力形式を指定する. TEXT, XML, JSON, YAMLが指定可能 TEXT ~v11 8 SETTINGS 設定パラメータに関する情報を出力する off v12 9 WAL 生成されたWAL情報を出力する off v13 10 GENERIC_PLAN 汎用的な計画での実行計画を出力する off v16 11 SERIALIZE 結果をシリアライズするコストを出力する。NONE,TEXT, BINARYが指定可能 NONE v17 12 MEMORY 実行計画時のメモリ使用量を出力する off v17