現在のクエリとトランザクションの分析
まずは基本から始めよう。PostgreSQLはSQLクエリやトランザクションを分析するためのすごいツールセットを持ってるんだ。たとえば、組み込み関数の current_query() と txid_current() を使えば、こんなことができるよ:
- 今実行中のSQLクエリを取得できる。
- どのトランザクションの中でクエリが実行されているか分かる。
- SQL操作をログに残して、あとで分析できる。
- トランザクションの問題を追跡できる。たとえば、コードが何かを期待してるのに、実際は全然違うことが起きてる時とか。
こういうのは、普通のデバッグ出力じゃ分からない時や、クエリの動きを「あとから」分析したい時にめっちゃ役立つよ。
組み込み関数のざっくり紹介
current_query() 関数
current_query() は、その接続で今実行されてるSQLクエリのテキストを返してくれる。「なんで分かるの?」って思うかもだけど、PostgreSQLは各接続の状態をちゃんと追跡してて、この関数でその「舞台裏」を覗けるんだ。
シンタックス:
SELECT current_query();
実行例:
-- 関数内でクエリを実行
DO $$
BEGIN
RAISE NOTICE '現在のクエリ: %', current_query();
END;
$$;
-- 結果:
-- NOTICE: 現在のクエリ: DO $$ BEGIN RAISE NOTICE '現在のクエリ: %', current_query(); END; $$;
この例から分かるように、current_query() は今実行中のクエリのテキストを教えてくれる。複雑なプロシージャを分析する時に超便利!今まさに何が実行されてるか分かるからね。
txid_current() 関数
トランザクションの話になると、txid_current() 関数がめっちゃ役立つ。これは今のトランザクションのユニークなIDを返してくれるんだ。1つのトランザクション内での操作の流れを追いたい時に特に便利!
シンタックス:
SELECT txid_current();
実行例:
BEGIN;
-- 現在のトランザクションIDを取得
SELECT txid_current();
-- 出力例:
-- 564 (例えばこのID)
-- トランザクションを終了
COMMIT;
こういうトランザクションIDはログの突き合わせや、操作の順番の分析、マルチユーザーシステムのデバッグにも使えるよ。
実際のタスクでの使い方例
- 実行中のクエリをログに残す。
プロシージャや関数の中にたくさんSQLクエリがある時、どこで何が起きてるか知りたいなら、今のSQLクエリをログに出すのがオススメ。例えば:
DO $$
DECLARE
current_txn_id BIGINT;
BEGIN
current_txn_id := txid_current();
RAISE NOTICE '現在のトランザクションID: %', current_txn_id;
RAISE NOTICE '現在のクエリ: %', current_query();
-- ここに他の操作を追加できるよ
END;
$$;
このコードは、トランザクションIDと今のクエリのテキストをコンソールに出してくれる。今何が実行されてるかバッチリ分かるね。
- トランザクションの問題を分析する。
例えば、ユーザーから「大量更新でデータが消えた!」ってクレームが来たとしよう。いくつかのプロシージャを1つのトランザクション内で実行してる場合、誰が原因か知りたいよね?こんな感じでやってみよう:
BEGIN;
-- トランザクションのログを追加
DO $$
BEGIN
RAISE NOTICE '現在のトランザクションID: %', txid_current();
END;
$$;
-- 「問題あり」なSQLクエリを実行
UPDATE orders
SET status = 'processed'
WHERE id IN (SELECT order_id FROM pending_orders);
COMMIT;
もし更新がうまくいかなかったら、どのトランザクションIDで変更しようとしたかすぐ分かる。エラーの特定も簡単だし、トランザクションの競合があったかも分かるよ。
- クエリをログに残して履歴を分析する。
今の問題を直すだけじゃなくて、どんなSQLクエリが実行されたか記録しておきたい時もあるよね。例えば、ログ用のテーブルを作って:
CREATE TABLE query_log (
log_time TIMESTAMP DEFAULT NOW(),
query_text TEXT,
txn_id BIGINT
);
こんな感じで current_query() と txid_current() を使ってクエリを記録できる:
DO $$
BEGIN
INSERT INTO query_log (query_text, txn_id)
VALUES (current_query(), txid_current());
END;
$$;
これで query_log テーブルに、実行されたクエリとそのトランザクションIDが全部残る。データベースの動きを分析するのに超便利!
実践的なケーススタディ
例1: トランザクションの監査
マルチユーザーシステムで操作を分析したい時、トランザクションID(txid_current)をログに残せば、1つのトランザクションごとに操作をグループ化できるよ。
DO $$
DECLARE
txn_id BIGINT;
BEGIN
txn_id := txid_current();
RAISE NOTICE 'トランザクション開始 ID: %', txn_id;
-- 何かの操作
UPDATE users SET last_login = NOW() WHERE id = 123;
RAISE NOTICE '現在のクエリ: %', current_query();
END;
$$;
例2: プロシージャのデバッグを簡単にする
複雑なプロシージャを呼び出して、何かおかしい時。関数のいろんな場所で current_query() のログを仕込めば、どのクエリが実行されたか見えるようになる:
CREATE OR REPLACE FUNCTION debugged_function() RETURNS VOID AS $$
BEGIN
RAISE NOTICE '更新前の現在のクエリ: %', current_query();
UPDATE data_table SET field = 'debugging';
RAISE NOTICE '更新後の現在のクエリ: %', current_query();
END;
$$ LANGUAGE plpgsql;
この関数を呼び出すと、2つの通知でそれぞれのSQLクエリが分かるよ。
使い方のコツ
current_query()を使って、マルチユーザーシステム内でどんなクエリが実行されてるかログに残そう。txid_current()は、どのタイミングでデータが追加・変更されたか、変更の出どころを分析するのにピッタリ。- 使い終わったら不要なログ出力は消しておこう。
RAISE NOTICEで通知を出し続けると、関数の実行が遅くなることもあるからね。
こういう組み込み関数は、データベースの「顕微鏡」みたいなもの。細かい動きを観察できるから、エラーを見つけたり、パフォーマンスを上げたり、複雑なシステムの中で何が起きてるか理解できるようになるよ。PostgreSQLの中では、君のデータベースがもう秘密を教える準備万端。あとは、その読み方を覚えるだけ!
GO TO FULL VERSION