みんな、サーバーが落ちたりユーザーの生活が大変になる前に問題を知りたいよね。PostgreSQLには通知を作ったりタスクを実行するためのツールがあるんだ:pg_notifyとpg_cron。これは、データベース用の目覚まし時計とスケジューラーみたいなものだよ。
例えば、君の通貨交換コースのデータベースで、突然どれかのプロセスが他をブロックしちゃったとしよう。毎回手動で状態をチェックする代わりに、通知を設定しておけばすぐ気付けるよ。データベースの状態を定期的にチェックしたいならpg_cronが便利。これから詳しく見ていこう!
データベースからの即時通知:pg_notify
まずはpg_notifyから。これはPostgreSQLに組み込まれてる関数で、データベースから特定の「チャンネル」に通知を送れるんだ。例えば長いクエリの終了やロックの検出、他のイレギュラーなイベントの通知に使えるよ。
pg_notifyのシンタックスは超シンプル:
NOTIFY <channel>, <message>;
channel— 通知を送るチャンネル名。message— 通知のテキスト。
pg_notifyの使い方例を見てみよう。 ロックが検出された時の通知を作ってみるよ:
DO $$
BEGIN
IF EXISTS (
SELECT 1
FROM pg_locks l
JOIN pg_stat_activity a
ON l.pid = a.pid
WHERE NOT l.granted
) THEN
PERFORM pg_notify('alerts', 'データベースでロック発生!');
END IF;
END $$;
このコードは未処理のロックがあるかチェックして、alertsチャンネルに通知を送るよ。
通知を受け取るには、別の接続でLISTENコマンドを使おう:
LISTEN alerts;
これで、pg_notifyがalertsチャンネルにメッセージを送ったら、コンソールに通知が表示されるよ。
例:
NOTIFY alerts, 'おい、ここでロック発生!';
別の接続でLISTEN alertsを実行していたら、すぐにこう表示される:
NOTIFY: おい、ここでロック発生!
pg_notifyはシンプルな通知だけじゃなくて、トリガーと組み合わせてデータ追加・変更・削除の自動通知にも使えるよ:
新しいレコードの通知
CREATE OR REPLACE FUNCTION notify_new_record()
RETURNS trigger AS $$
BEGIN
PERFORM pg_notify('table_changes', 'テーブルに新しいレコードが追加されたよ!');
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER record_added
AFTER INSERT ON your_table
FOR EACH ROW EXECUTE FUNCTION notify_new_record();
これでyour_tableに新しいレコードが追加されるたびに通知が届くよ。
トリガーや組み込み関数については、もうちょっと進んだら詳しくやるからね :P
よくあるミスとその回避法
LISTENを使ってるのに通知が見えない場合は、次をチェックしよう:
- 通知を送ってるのと同じ接続で作業してない?
- チャンネル名が正しいか確認しよう。
pg_notifyをコミット済みのトランザクション内で呼んでるか確認しよう(COMMIT)。
PostgreSQLのタスクスケジューラー:pg_cron
pg_cronはPostgreSQL用の拡張で、Linuxのクラシックなcronみたいにスケジュールでタスクを実行できるよ。例えば、ロックの定期チェックや統計の収集を自動化できる。
pg_cronでタスクを作成する
pg_cronがインストールされて準備OKなら、毎日logsテーブルの古いレコードを消すタスクを作ってみよう。
SELECT cron.schedule('古いログの削除',
'0 0 * * *',
$$ DELETE FROM logs WHERE created_at < NOW() - INTERVAL '30 days' $$);
これが何をしてるか説明するね:
'0 0 * * *'— コマンドの実行スケジュール(毎日0時)。DELETE FROM logs ...— cronが実行するSQLクエリ。
タスクの一覧を見る
pg_cronで実行中のタスクを全部見るには:
SELECT * FROM cron.job;
タスクの無効化
タスクを無効にするには:
SELECT cron.unschedule(jobid);
jobidはタスクのIDで、cron.jobテーブルから確認できるよ。
pg_cronの便利な例
クエリのアクティビティを定期チェック
5分ごとに長時間実行中のクエリをチェックするタスクを作ろう:
SELECT cron.schedule('長いクエリのチェック',
'*/5 * * * *',
$$ SELECT pid, query, state
FROM pg_stat_activity
WHERE state = 'active'
AND now() - query_start > INTERVAL '5 minutes' $$);
このタスクは5分以上実行中のクエリを探してくれるよ。
外部システムとの連携
pg_notifyもpg_cronも、SlackやTelegram、監視システム(Prometheusとか)と連携できるよ。
Telegram
pg_notifyとTelegramボットを組み合わせて通知を送ることもできる。基本はPythonとかで通知を受け取ってTelegramに転送するスクリプトを書く感じ。
シンプルなPythonボットの例:
import psycopg2
import telegram
# PostgreSQLに接続
conn = psycopg2.connect("dbname=your_database user=your_user")
# Telegramボットを作成
bot = telegram.Bot(token='your_telegram_bot_token')
# 通知をリッスンするためのカーソルを開く
conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
cur = conn.cursor()
cur.execute("LISTEN alerts;")
# 通知を待ち受け
print("通知を待ってるよ...")
while True:
conn.poll()
while conn.notifies:
notify = conn.notifies.pop()
print("通知を受信:", notify.payload)
bot.send_message(chat_id='your_chat_id', text=notify.payload)
これでpg_notify経由の通知をボットが受け取ってくれるよ。
pg_notifyとpg_cronはいつ使う?
pg_notifyは即時反応が欲しい時(例えばロック発生時に管理者へ通知)に使おう。
pg_cronは定期的なタスク(クエリのアクティビティチェックや古いデータの掃除)に使うのがベスト。
注意点と落とし穴
pg_notifyは即時通知だけど履歴は残らない。ファイルログや外部システムと組み合わせるのがオススメ。
pg_cronはタスクを頻繁に実行しすぎると予想外の負荷になることも。スケジュールに追加する前に必ずクエリをテストしよう。
これでデータベース監視を最適化して管理を自動化する準備はバッチリ!アラートを設定して、ただのSQLプログラマーじゃなくDBAを目指そう!
GO TO FULL VERSION