DataBase / PostgreSQL / レポート取得ガイド
pg_stat_statements による取得とセクション定義
拡張モジュール pg_stat_statements を使って、Oracle AWR の SQL Statistics セクション相当の
重い SQL・累積実行時間・呼び出し回数・I/O 統計・WAL 統計を取得する方法と、
各列のセクション定義を詳しく解説します。
1. pg_stat_statements の有効化
# shared_preload_libraries に追加(再起動が必要)
shared_preload_libraries = 'pg_stat_statements'
# オプション設定
pg_stat_statements.max = 10000 # 追跡する SQL の最大数(デフォルト:5000)
pg_stat_statements.track = all # all=全クエリ, top=トップレベルのみ, none=無効
pg_stat_statements.track_utility = on # COPY・VACUUM などのユーティリティも追跡
pg_stat_statements.save = on # 再起動後も統計を保持
-- 拡張をインストール(superuser 権限が必要)
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- インストール確認
SELECT * FROM pg_extension WHERE extname = 'pg_stat_statements';
-- バージョン確認
SELECT pg_stat_statements_info();
⚠️ shared_preload_libraries の変更は再起動が必要
postgresql.conf に追加後、PostgreSQL を再起動してください。
CREATE EXTENSION は再起動後に実行します。
既に他のライブラリが設定されている場合はカンマ区切りで追記します。
2. 累積実行時間の多い SQL(AWR: SQL ordered by Elapsed Time 相当)
SELECT
ROUND(total_exec_time::numeric, 2) AS total_exec_ms,
calls,
ROUND((total_exec_time / calls)::numeric, 2) AS avg_exec_ms,
ROUND(min_exec_time::numeric, 2) AS min_exec_ms,
ROUND(max_exec_time::numeric, 2) AS max_exec_ms,
ROUND(stddev_exec_time::numeric, 2) AS stddev_exec_ms,
rows,
ROUND((100 * total_exec_time / SUM(total_exec_time) OVER())::numeric, 2) AS pct_total,
left(query, 100) AS query_preview
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;
3. 実行回数の多い SQL(AWR: SQL ordered by Executions 相当)
SELECT
calls,
ROUND(total_exec_time::numeric, 2) AS total_exec_ms,
ROUND((total_exec_time / calls)::numeric, 2) AS avg_exec_ms,
rows,
ROUND((rows::numeric / calls), 2) AS avg_rows,
left(query, 100) AS query_preview
FROM pg_stat_statements
ORDER BY calls DESC
LIMIT 20;
4. I/O の多い SQL(AWR: SQL ordered by Gets 相当)
SELECT
calls,
shared_blks_hit + shared_blks_read AS total_blks,
shared_blks_hit,
shared_blks_read,
ROUND(shared_blks_hit::numeric /
NULLIF(shared_blks_hit + shared_blks_read, 0) * 100, 2) AS hit_ratio,
shared_blks_dirtied,
shared_blks_written,
local_blks_hit + local_blks_read AS local_blks_total,
temp_blks_read,
temp_blks_written,
left(query, 100) AS query_preview
FROM pg_stat_statements
ORDER BY shared_blks_read DESC
LIMIT 20;
5. pg_stat_statements 全列定義
セクション定義: pg_stat_statements
識別情報
| 列名 | 説明 | Oracle AWR 対応 |
|---|---|---|
| userid | SQL を実行したユーザーの OID。pg_roles.oid と結合で名前に変換。 |
Parsing User ID |
| dbid | SQL が実行されたデータベースの OID。 | — |
| toplevel | (PostgreSQL 14+)トップレベルの SQL として実行されたか。false はストアドプロシージャ内などからの呼び出し。 |
— |
| queryid | 正規化後のクエリテキストのハッシュ値。同一パターンの SQL を識別するキー。 | SQL_ID |
| query | 正規化されたクエリテキスト(リテラル値は $1/$2... に置換)。 |
SQL_TEXT |
実行統計
| 列名 | 説明 | Oracle AWR 対応 |
|---|---|---|
| calls | 累積実行回数。 | Executions |
| total_exec_time | 累積実行時間(ms)。プランニング時間は含まない。Oracle の Elapsed Time に相当。 | Elapsed Time |
| min_exec_time | 最小実行時間(ms)。 | — |
| max_exec_time | 最大実行時間(ms)。スパイクの検出に使う。 | — |
| mean_exec_time | 平均実行時間(ms)。 | Elapsed Time / Executions |
| stddev_exec_time | 実行時間の標準偏差(ms)。大きい場合は実行時間が不安定。 | — |
| total_plan_time | (PostgreSQL 13+)累積プランニング時間(ms)。高い場合は実行計画のキャッシュを検討。 | — |
| rows | 累積返却行数(SELECT)または影響行数(INSERT/UPDATE/DELETE)。 | Rows Processed |
ブロック I/O 統計
| 列名 | 説明 | Oracle AWR 対応 |
|---|---|---|
| shared_blks_hit | 共有バッファキャッシュからヒットした累積ブロック数。 | Buffer Gets(Logical Reads) |
| shared_blks_read | ディスクから読み込んだ累積ブロック数(キャッシュミス)。 | Physical Reads |
| shared_blks_dirtied | ダーティにした累積ブロック数(更新が発生したブロック)。 | — |
| shared_blks_written | 共有バッファから書き込んだ累積ブロック数。 | Physical Writes |
| local_blks_hit | ローカルバッファ(一時テーブル用)からヒットした累積ブロック数。 | — |
| local_blks_read | ローカルバッファのキャッシュミスによるディスク読み込み数。 | — |
| temp_blks_read | 一時ファイルから読み込んだ累積ブロック数(ソート・ハッシュ結合の work_mem 超過)。 |
Sorts (disk) |
| temp_blks_written | 一時ファイルに書き込んだ累積ブロック数。 | — |
I/O 時間統計(track_io_timing = on が必要)
| 列名 | 説明 | Oracle AWR 対応 |
|---|---|---|
| blk_read_time | ディスク読み込みに費やした累積時間(ms)。 | db file sequential / scattered read |
| blk_write_time | ディスク書き込みに費やした累積時間(ms)。 | db file parallel write |
| temp_blk_read_time | (PostgreSQL 15+)一時ファイルの読み込み時間(ms)。 | — |
| temp_blk_write_time | (PostgreSQL 15+)一時ファイルへの書き込み時間(ms)。 | — |
WAL 統計(PostgreSQL 13+)
| 列名 | 説明 | Oracle AWR 対応 |
|---|---|---|
| wal_records | 生成した WAL レコード数。更新系 SQL の Write 量の指標。 | Redo Size |
| wal_fpi | 生成した WAL フルページイメージ数(チェックポイント後の初回更新時)。 | — |
| wal_bytes | 生成した WAL の合計バイト数。 | Redo Writes(bytes) |
💡 track_io_timing の有効化
blk_read_time / blk_write_time を取得するには
postgresql.conf に track_io_timing = on が必要です。
OS のタイマー精度に依存するためオーバーヘッドがありますが、
I/O ボトルネックの特定には非常に有効です。
6. スナップショット差分による期間分析
pg_stat_statements は累積値であるため、特定期間の統計を取るには 開始・終了時点のスナップショットを保存して差分を計算します。
-- スナップショット保存テーブル
CREATE TABLE pgss_snapshot AS
SELECT
now() AS snap_time,
queryid,
query,
calls,
total_exec_time,
rows,
shared_blks_hit,
shared_blks_read
FROM pg_stat_statements
WHERE 1 = 0; -- 構造だけ作成
-- スナップショット取得(計測開始時)
INSERT INTO pgss_snapshot
SELECT now(), queryid, query, calls, total_exec_time, rows, shared_blks_hit, shared_blks_read
FROM pg_stat_statements;
-- 計測終了時にもう一度 INSERT してから差分クエリ
WITH
s1 AS (SELECT * FROM pgss_snapshot WHERE snap_time = (SELECT MIN(snap_time) FROM pgss_snapshot)),
s2 AS (SELECT * FROM pgss_snapshot WHERE snap_time = (SELECT MAX(snap_time) FROM pgss_snapshot))
SELECT
s2.query,
s2.calls - s1.calls AS calls_diff,
ROUND((s2.total_exec_time - s1.total_exec_time)::numeric, 2) AS exec_ms_diff,
ROUND(((s2.total_exec_time - s1.total_exec_time) /
NULLIF(s2.calls - s1.calls, 0))::numeric, 2) AS avg_exec_ms,
s2.rows - s1.rows AS rows_diff,
s2.shared_blks_read - s1.shared_blks_read AS phys_reads_diff
FROM s1 JOIN s2 USING (queryid)
WHERE s2.calls > s1.calls
ORDER BY exec_ms_diff DESC
LIMIT 20;
7. 統計のリセット
-- 全統計をリセット(計測開始点のリセット)
SELECT pg_stat_statements_reset();
-- 特定のクエリのみリセット(PostgreSQL 12+)
SELECT pg_stat_statements_reset(userid, dbid, queryid)
FROM pg_stat_statements
WHERE query LIKE '%target_table%';