PostgreSQL はオープンソースで拡張性が高いデータベース🦊
業務では Oracle を使うことが多いのですが、個人的には PostgreSQL がとても好きです。
理由はいろいろありますが、ちょっと変わった機能が多くて触っていて楽しいこと、そして 象のアイコンが可愛いことが大きいです。
本当はこの記事も「象」をナビゲーターにして書こうと思ったのですが、
象は鼻でしかナビゲートできないため、やむなく断念しました。
読んでくださる皆さまには、心の目で象を感じていただけると嬉しいです。
さて、今日(7/13)まで「最新 PostgreSQL の新機能を現場に活かした体験を共有しよう」というキャンペーンが開催されており、
今さらながら慌てて投稿しています。
そのため、もし誤字脱字があっても、どうかやさしく見逃していただけると助かります。
そんなわけで、最新機能というよりは AWSのRDS PostgreSQL のちょっとした活用方法の紹介になりますが、
少しでも誰かのヒントになれば嬉しいです。
1.【機能紹介】⏰ pg_cron機能で、SQL定期実行をDB内だけで実現
まず最初に、pg_cron 機能について紹介します。
pg_cron は PostgreSQL 内部で定期タスクを管理できる拡張機能です。
通常、バッチ処理や定期実行は Linux の cron や AWS Lambda などの外部サービスを利用する必要がありますが、pg_cron を利用すると SQL コマンドだけでスケジュール登録や管理ができ、データベース内だけで自動化を実現できます。
今回は動作確認として、1分ごとにテーブルへダミーデータを登録するジョブを作成し、DBのみでSQLの定期実行ができることを確認します。
① パラメータグループ設定
まず、pg_cron を有効化するため、RDS PostgreSQL が利用しているパラメータグループで下記を設定します。
パラメーター「shared_preload_libraries」
値:「pg_cron」
このパラメータの設定により、pg_cron機能が有効化されます。

② pg_cron拡張を作成
DB内で以下のSQLを実行します。
CREATE EXTENSION pg_cron;
このコマンドにより、パラメータグループで有効化した pg_cron が実際に利用可能になります。
③動作確認用テーブル作成
まずはダミーデータ登録用のテーブルを作成します。
CREATE TABLE dummy_data (
id serial PRIMARY KEY,
created_at timestamp NOT NULL DEFAULT now(),
note text
);
④ 定期実行ジョブを登録
それでは、いよいよ1分ごとにデータを登録するジョブを作成します。
SELECT cron.schedule(
'insert_dummy_every_minute',
'* * * * *',
$$INSERT INTO dummy_data (note)
VALUES ('hello from pg_cron');$$
);
⑤ ジョブ登録確認
以下のSQLでジョブを確認します。
SELECT * FROM cron.job;
⑥ データ登録確認
では、数分待った後に、登録を確認しましょう
(ちょっとお料理番組みたいですね……「では、こちらが数分後のデータです」みたいな感じで🦊)
SELECT *
FROM dummy_data
ORDER BY id DESC
LIMIT 10;
登録したスケジュールどおりに、1分ごとにデータが登録されていることを確認できます。
⑧CloudWatch Logs で確認
pg_cron の実行結果は CloudWatch Logs に出力されます。
2.【機能紹介】🗒️ pg_stat_statements機能で、SQL実行結果を簡単解析
続いて紹介するのは pg_stat_statements です。
pg_stat_statements は PostgreSQL 標準の拡張機能であり、実行された SQL の統計情報を収集できる分析ツールです。
以下のような情報を取得できます。
- SQL実行回数
- 平均実行時間
- 最大実行時間
- I/O情報
- バッファ利用状況
AWS の RDS PostgreSQL や Aurora PostgreSQL では、パラメータグループで有効化するだけで利用できます。
どの SQL が負荷の原因になっているかを把握する際の第一歩として非常に便利な機能です。
① パラメータグループ設定
まず、パラメーター「shared_preload_libraries」を選択し、「pg_stat_statements」を追加します。

② 拡張機能作成
CloudShell から接続して以下を実行します。
CREATE EXTENSION pg_stat_statements;
これで利用準備完了です。
③ 分析対象データ作成
以下のSQLを3回実行します。
SELECT pg_sleep(sleeptime), sleeptime
FROM (
SELECT floor(random() * 100) + 1 AS sleeptime
) AS t;
④ 実行結果を分析
では、いよいよ下記のpg_stat_statementsのSQLを実行して、先ほど実行したSQLの平均時間を取得します。
SELECT
(mean_exec_time/1000) AS 平均実行時間_秒,
calls AS 実行回数,
query AS 実行SQL
FROM pg_stat_statements
WHERE query LIKE '%sleeptime%';
pg_stat_statementsのSQLを実行するだけで、簡単にSQL解析情報を取得できました。
pg_stat_statements の魅力
pg_stat_statements の大きなメリットは、
SQLを実行するだけで分析情報が参照できることです。
専用ツールや複雑な監視環境を構築する必要はなく、
SELECT *
FROM pg_stat_statements;
を実行するだけで分析を開始できます。
性能改善やチューニングの第一歩として非常に有効な機能です。
また、本記事で紹介した項目以外にも多数の統計情報を取得できます。
詳細は PostgreSQL 公式ドキュメントをご参照ください。
- PostgreSQL公式ドキュメント
https://www.postgresql.org/docs/current/pgstatstatements.html
注意事項とお詫び
pg_sleep の実行時間にはミリ秒単位の誤差が含まれるため、手計算値と pg_stat_statements の結果がわずかに異なる場合があります。それため、実はすこし誤差があります。
3.【機能連携案】RDS と CloudWatch をつないで SQL 実行を見える化
RDS PostgreSQL の機能である pg_cron(SQL の定期実行機能) と
pg_stat_statements(SQL の解析機能) を紹介しました。
ここでは、この 2 つの機能に CloudWatch Logs を組み合わせて、
SQL の平均実行時間をグラフ化する仕組み を構築します。
🏗️ 構築手順
① SQL の実行 & CloudWatch Logs 送信
1 分ごとに実行される SQL と、5 分ごとに「直近 5 分間の SQL の平均実行時間」を取得する SQL を pg_cron に登録します。
取得した結果を CloudWatch Logs に出力します。
② メトリクスフィルターの設定
出力された CloudWatch Logs に対してメトリクスフィルターを設定し、
グラフ化の元データとなるメトリクスを抽出します。
③ ダッシュボードの作成
作成したメトリクスフィルターのデータをもとに CloudWatch Dashboard を構築し、
平均 SQL 実行時間の推移をグラフとして可視化します。
3-1.🚚 SQL 実行平均実行時間を CloudWatch Logs に送信
① ランダム実行時間の SQL を 1 分ごとに定期実行
ではまず、下記SQLを実行します。このSQLは1~50秒までのランダムな実行時間になるSQLを1分毎に定期実行します。
-- 1分毎にSQLを実行する
SELECT cron.schedule(
'random_sleep_job',
'* * * * *',
$$
-- 実行時間は1~50秒まで
SELECT pg_sleep(sleeptime), sleeptime
FROM (
SELECT floor(random() * 50) + 1 AS sleeptime
) AS t;
$$
);
② ランダム実行時間の平均値を 5 分ごとに計測し CloudWatch Logs に出力
先ほど登録したランダム実行時間のSQLの平均時間を計測するSQLを五分毎に定期実行します。
実行平均時間の結果を、avg_secに入れて、CloudWathLogに{"metric_type": "pg_stats", "avg_sec": %s}のフォーマットで出力します。
SELECT cron.schedule(
'avg_exec_time_job',
'*/5 * * * *',
$$
DO $do$
DECLARE
avg_sec numeric;
json_output text;
BEGIN
-- 1. sleep クエリの平均実行時間(秒)を取得
SELECT COALESCE(ROUND((avg(mean_exec_time) / 1000)::numeric, 4), 0)
INTO avg_sec
FROM pg_stat_statements
WHERE query LIKE '%pg_sleep%';
-- 2. CloudWatch 用のログ出力
json_output := format(
'{"metric_type": "pg_stats", "avg_sec": %s}', avg_sec
);
-- CONTEXT が付かないログ出力
RAISE LOG '%', json_output;
-- 3. 累積統計をリセット(次回はこの5分間のデータのみが対象)
PERFORM pg_stat_statements_reset();
END;
$do$
$$
);
③ スケジュール登録確認
下記SQLを実行し、スケジュール登録を確認します。
SELECT jobid, schedule, command, jobname
FROM cron.job
ORDER BY jobid;
④ CloudWatch Logs でログを確認します。
pg_cron の SQL が CloudWatch Logs に出力されていることを確認します。

3-2. 🔎CloudWathLogsのLogをメトリクスフィルターで抽出
次にCloudWatch Logs に出力された JSON ログから、
平均 SQL 実行時間(avg_sec)をメトリクスとして抽出 します。
メトリクスフィルターとは、ログの中から特定の値を抽出し、
CloudWatch のメトリクスとして登録する機能です。
① メトリクスフィルターの作成
CloudWatchLogからメトリクスフィルターの作成ボタンを押下します。

② フィルターパターンを設定
フィルターパターンを設定します。
{ $.avg_sec = * }
フィルターパターン解説
-
{ }… JSON フィルター構文 -
$.… ルートの JSON を参照 -
avg_sec… 抽出したいフィールド -
*… すべての値を対象
③ 抽出結果確認
④ メトリクスフィルターの設定
下記のようにメトリクスフィルターを設定します。この設定により、秒ごとにpostgerから出力されたSQLの実行平均時間が抽出されます。
- フィルター名:avgFilter(任意)
- メトリクス名前空間:Custom/RDS(任意)
- メトリクス名:AverageExecutionTime(任意)
-
メトリクス値:
$.avg_sec - 単位:秒
3-3.📉抽出した値からダッシュボードでグラフを作成
メトリクスフィルターを作成したので、その抽出結果をグラフ化するために、カスタムダッシュボードを作成します。
ダッシュボードとは、CloudWatch のメトリクスをグラフや数値パネルとしてまとめて表示できる監視用の画面です。CPU 使用率やディスク I/O、今回のような SQL 実行時間など、複数のメトリクスを一つの画面に集約して確認できます。
① ダッシュボードの作成
まず、CloudWatch コンソールの 「ダッシュボード」 から 「ダッシュボードの作成」 をクリックします。
② 名前の設定
ダッシュボード名に任意の名前を設定します。
③ ウィジェットタイプの選択
ウィジェットのタイプを選択します。
今回は 「線」 を選択します。
④ メトリクスの選択
メトリクスグラフが表示されたら、メトリクスフィルターで設定した名前空間を指定します。
本記事では、カスタム名前空間である 「Custom/RDS」 を選択します。

⑤ ディメンションなしのメトリクスを選択
⑥表示されたメトリクス名から、メトリクスフィルターの作成で設定したメトリクスを選択します。
今回は、「AverageExecutionTime」を選択します。

⑦ついにグラフ表示
対象データが存在する期間を指定し、 RDS PostgreSQL における SQL の実行時間を CloudWatch のメトリクスフィルター で抽出した結果を、 グラフとして表示されることを確認します。
🎉 まとめ
RDS PostgreSQL の pg_cron(定期実行) と
pg_stat_statements(SQL 解析) を組み合わせることで、
SQL の平均実行時間を自動収集し、CloudWatch Logs に連携して可視化 できました。
この構成は RDS PostgreSQL 標準機能 × AWS 標準サービスのみ で完結しており、
外部ツールや追加ライセンスは不要です。
コストを抑えながら、高い可視性を実現できます。
おわりに
PostgreSQLとAWS機能の掛け合わせをご紹介しましたが、PostgreSQLの魅力はこんなものじゃないです。
PostgreSQL 19の新機能、IO統計やAutovacuumの改善などが発表
DB上でプロパティグラフのクエリを実行できるそうです。なんだか面白そう!
今回は時間不足でご紹介しきれなかったのですが、PostgreSQLは楽しいです。今回は時間の都合でご紹介しきれなかった部分も多いのですが、PostgreSQL は触っていて本当に楽しいデータベースです。
もし少しでも興味を持っていただけたら、とても嬉しいです



















