--- title: "pg_cron を使用する" slug: "clouddbforpostgresql-pgcron" updated: 2026-10-20T09:03:46Z published: 2026-10-20T09:03:46Z canonical: "guide.ncloud-docs.com/clouddbforpostgresql-pgcron" --- > ## Documentation Index > Fetch the complete documentation index at: https://guide.ncloud-docs.com/llms.txt > Use this file to discover all available pages before exploring further. # pg_cron を使用する VPC環境で利用できます。 Cloud DB for PostgreSQLで pg_cron extensionを提供していますので、以下のご利用ガイドをご参照ください。pg_cronは、PostgreSQL内部で cron式に基づいて SQLタスクを予約実行する extension機能です。 ## コンソールによる extensionのインストール Cloud DB For PostgreSQLでは superuser権限を提供していないので、コンソールを通じて superuser権限が必要な extensionをインストールできます。詳細は、以下のガイドをご参照ください。 - [Extensionのインストール](/docs/ja/clouddbforpostgresql-postgresqlextension) pg_cronをインストールする際は、タスクを予約する対象のデータベースを選択します。インストールプロセス中には DBサーバが再起動され、HA(高可用性)構成では Failover方式によりサーバが順次再起動されます。 注意 - pg_cronは、PostgreSQLクラスタごとに1つのデータベースにのみインストールできます。既にインストールされている場合、別のデータベースに追加でインストールすることはできません。 - インストール時に選択したデータベースの DB ownerアカウントにのみ、pg_cronの使用権限が付与されます。他の DBユーザーには権限が付与されません。 - したがって、pg_cronを使用するには、当該データベースの DB ownerアカウントでログインする必要があります。 - DB ownerアカウントには、権限を再付与する権限(GRANT OPTION)がないため、DB ownerアカウントは他の DBユーザーに対して cronスキーマの権限を付与(GRANT)することはできません。 ## pg_cron とは pg_cronをインストールすると、対象のデータベースに `cron` スキーマが作成され、以下の構成要素を通じてタスクを予約・管理します。Cloud DB for PostgreSQLでは superuser権限が提供されないため、以下の表の **DB ownerアカウント使用**の項目に従い、一部の関数は使用できません。 | 区分 | 名前 | 説明 | DB ownerアカウント使用 | | --- | --- | --- | --- | | テーブル | cron.job | 予約されたタスク定義 | 照会(自分のタスク) | | テーブル | cron.job_run_details | タスク実行履歴 | 照会・削除(自分の履歴) | | 関数 | cron.schedule | タスク予約 | 使用可能 | | 関数 | cron.unschedule | タスク削除 | 使用可能 | | 関数 | cron.schedule_in_database | 他のデータベースのタスク予約 | サポートしない | | 関数 | cron.alter_job | 予約されたタスクの変更 | サポートしない | 予約されたタスクは、そのタスクを登録したユーザーの権限で実行されます。登録済みのユーザーがアクセスできないテーブルに対しては、タスクを行うことはできません。 参考 - Cloud DB for PostgreSQLでは superuser権限が提供されていないため、DB ownerアカウントでは `cron.schedule`(タスク予約)、`cron.unschedule`(タスク削除)および `cron.job`·`cron.job_run_details` 照会を使用できます。 - `cron.schedule_in_database`(他のデータベースのタスク予約)および `cron.alter_job`(予約されたタスクの変更)は、DB ownerアカウントには提供されません。呼び出すと、`permission denied for function` エラーが発生します。これら2つの関数は、`username` 引数として他のアカウントの権限でタスクを実行できるため、セキュリティ上の理由から制限されています。 - 予約されたタスクのスケジュールやコマンドを変更するには、`cron.unschedule`で一度削除してから再度予約します。 - pg_cronタスクは Primaryサーバでのみ実行されます。Failoverが発生すると、新しい Primaryサーバで予約されたタスクが自動的に継続して実行されます。 ## タスクの予約と管理 インストール時に選択したデータベースに DB ownerアカウントでアクセスし、タスクを予約します。 参考 - Cloud DB for PostgreSQLでは、セキュリティ上の理由から新規データベースでの `public` スキーマの使用は推奨されません。そのため、別途スキーマを作成して使用します。 - 予約タスクの SQLでは、スキーマを含む名前(`sales.orders`)を使用することをお勧めします。タスクは、`search_path` 設定に関係なく動作してこそ安全です。 #### タスク予約 `cron.schedule(job_name, schedule, command)` 形式で予約します。 ``` -- 毎日03:00に sales.ordersテーブルの VACUUM ANALYZEを実行 SELECT cron.schedule('nightly-vacuum-orders', '0 3 * * *', 'VACUUM ANALYZE sales.orders'); -- 毎週日曜日05:00に、90日以上前の注文を削除 SELECT cron.schedule('purge-old-orders', '0 5 * * 0', $$DELETE FROM sales.orders WHERE ordered_at < now() - interval '90 days'$$); ``` 参考 - スケジュールには、標準の cron式(分、時、日、月、曜日)が使用されます。 - `'10 seconds'`のように、秒単位の間隔も指定できます。 参考 - pg_cronは、予約されたタスクをバックグラウンドワーカーとして実行します(`cron.use_background_workers`が `on`に設定されます)。同時に実行できるタスク数は、サーバのバックグラウンドワーカー数によって制限されます。 - 複数のタスクの実行時間が重なると、同時実行の制限に達する可能性があるため、負荷の高いタスクや多数のタスクについては、実行時間を分散させることをお勧めします。 - 同じタスクの前回の実行が終了していない場合、次の実行は重複して実行されることなく、前回の実行が終了するまで待機します。 #### タスクの照会と変更 予約されたタスクは、`cron.job`で照会します。スケジュールやコマンドを変更する際は `cron.alter_job`を使用できないため、`cron.unschedule`で削除してから同じ名前で再度予約します。 ``` -- 予約されたタスクを照会(自分が登録したタスクのみ表示) SELECT jobid, jobname, schedule, command, active FROM cron.job; -- スケジュール変更: 既存のタスクを削除した後、新しいスケジュールで再度予約します。 SELECT cron.unschedule('purge-old-orders'); SELECT cron.schedule('purge-old-orders', '0 6 * * 0', $$DELETE FROM sales.orders WHERE ordered_at < now() - interval '90 days'$$); -- タスク削除 SELECT cron.unschedule('nightly-vacuum-orders'); ``` ## ユースケース: 日別売上集計の取り込み 毎日早朝に前日の注文を集計し、要約テーブルに取り込むユースケースです。以下のユースケースは、スキーマやテーブルの作成から検証まで、そのまま実行できます。このユースケースでは、pg_cronがインストールされたデータベースを `maindb`、当該データベースの DB ownerを `mainowner`と仮定します。すべてのタスクは、`maindb`に `mainowner`アカウントでアクセスしてから登録します。 ``` -- maindb に mainownerアカウントでアクセスします。 \c maindb mainowner ``` ``` -- 1. 使用するスキーマを作成します(Cloud DB for PostgreSQLでは、publicスキーマの使用は推奨されていないため、別のスキーマを使用します)。 CREATE SCHEMA sales; -- 2. ソース注文テーブルを作成し、サンプルデータを入力します(運用中のテーブルがある場合は省略します)。 CREATE TABLE sales.orders ( order_id bigserial PRIMARY KEY, amount numeric(12,2) NOT NULL, ordered_at timestamptz NOT NULL DEFAULT now() ); INSERT INTO sales.orders (amount, ordered_at) VALUES (15000, current_date - 1 + time '09:30'), -- 昨日の注文 (32000, current_date - 1 + time '13:10'), -- 昨日の注文 (8900, current_date - 1 + time '20:05'), -- 昨日の注文 (47000, current_date + time '08:00'); -- 今日の注文(昨日の集計には含まれない) -- 3. 集計結果を保存するための要約テーブルを作成します。 CREATE TABLE sales.daily_sales_summary ( sales_date date PRIMARY KEY, order_cnt integer NOT NULL, total_amount numeric(14,2) NOT NULL ); -- 4. まず、動作を迅速に検証するために、毎分実行するようにタスクを予約します。 -- スキーマを含む名前を使用し、同じ日付で再実行されても重複しないよう、ON CONFLICTで更新します。 SELECT cron.schedule( 'rollup-daily-sales', '* * * * *', $$INSERT INTO sales.daily_sales_summary (sales_date, order_cnt, total_amount) SELECT current_date - 1, count(*), coalesce(sum(amount), 0) FROM sales.orders WHERE ordered_at >= current_date - 1 AND ordered_at < current_date ON CONFLICT (sales_date) DO UPDATE SET order_cnt = EXCLUDED.order_cnt, total_amount = EXCLUDED.total_amount$$ ); -- 5. 1~2分ほど待ってから、取り込み結果とタスク実行履歴を確認します。 SELECT sales_date, order_cnt, total_amount FROM sales.daily_sales_summary ORDER BY sales_date DESC LIMIT 10; SELECT jobid, status, return_message, start_time FROM cron.job_run_details WHERE jobid = (SELECT jobid FROM cron.job WHERE jobname = 'rollup-daily-sales') ORDER BY start_time DESC LIMIT 5; -- 6. 正常に動作することを確認したら、テストタスクを削除して運用スケジュール(毎日00:05)として再度予約します。 -- (cron.alter_jobは使用できないため、unscheduleを行った後、再度予約します)。 SELECT cron.unschedule('rollup-daily-sales'); SELECT cron.schedule( 'rollup-daily-sales', '5 0 * * *', $$INSERT INTO sales.daily_sales_summary (sales_date, order_cnt, total_amount) SELECT current_date - 1, count(*), coalesce(sum(amount), 0) FROM sales.orders WHERE ordered_at >= current_date - 1 AND ordered_at < current_date ON CONFLICT (sales_date) DO UPDATE SET order_cnt = EXCLUDED.order_cnt, total_amount = EXCLUDED.total_amount$$ ); ``` 参考 - 集計基準日(`current_date`)は、セッションおよびサーバのタイムゾーンによって決定されます。タイムゾーンによって集計対象の日付が異なる場合があるため、意図した期間が正しく集計されているかご確認ください。 - テスト時には、毎分(`* * * * *`)の実行で動作を素早く確認し、`cron.unschedule` 後に運用スケジュールに再度予約します(`cron.alter_job`は、DB ownerアカウントでは使用できません)。 ## 実行履歴のモニタリング `cron.job_run_details`で、タスクの実行履歴を確認できます。自分が登録したタスクの履歴のみ照会されます。 ``` -- 最近の実行履歴を照会 SELECT jobid, jobname, status, return_message, start_time, end_time FROM cron.job_run_details ORDER BY start_time DESC LIMIT 20; ``` `cron.job_run_details`は自動的にクリーンアップされないため、以下のようにクリーンアップタスクを予約することをお勧めします。 ``` -- 毎週日曜日05:00に、30日より前の実行履歴を削除 SELECT cron.schedule('cleanup-cron-history', '0 5 * * 0', $$DELETE FROM cron.job_run_details WHERE end_time < now() - interval '30 days'$$); ``` 参考 - `cron.job_run_details`はタスクの実行ごとに蓄積されるため、クリーンアップタスクを予約しないとテーブルのサイズがどんどん大きくなってしまいます。