「本番環境がなんか重い気がする……」
そんなアラートが飛んできたとき、真っ先に確認すべき場所はどこだと思いますか? CPU使用率? メモリの空き? それも大事ですが、データベースエンジニアとして僕が最初に見るのは、間違いなく「実行に時間がかかっているクエリ」です。
PostgreSQLでその「犯人」を特定するための最も基本的、かつ強力な武器が `log_min_duration_statement` です。今日は、マニュアルの解説だけでは見えてこない、実務での「使いこなし方」についてお話しします。
—
なぜ log_min_duration_statement なのか
PostgreSQLのログ設定にはいくつか種類がありますが、この設定は「指定したミリ秒数を超えたクエリを、そのままログファイルに書き出す」という至極シンプルなものです。
設定方法は簡単。`postgresql.conf` を開いて、こう書くだけです。
1秒(1000ms)以上かかったクエリをログに出力する
log_min_duration_statement = 1000
これだけで、裏でヒーヒー言っているクエリが丸裸になります。「何が」実行され、「どのくらい」かかったのか。チューニングは、ここから始まります。
実務で意識すべき「魔法の数値」
よくある質問として「何ミリ秒に設定するのが正解ですか?」と聞かれます。
僕の答えは、「まずは 1000ms (1秒) から始めて、徐々に締めていく」です。
いきなり `log_min_duration_statement = 0` (すべてのクエリを記録)に設定する勇気があるなら止はしませんが、高負荷な環境でこれをやると、ログファイルが爆発的に肥大化し、ディスクI/Oが枯渇して本末転倒な事態になります。
1. フェーズ1: 1000msで設定し、明らかにヤバい「死のクエリ」を駆除する。
2. フェーズ2: 500ms、300msと段階的に下げ、アプリの体感速度を向上させる。
3. フェーズ3: 必要に応じて `pg_stat_statements` と併用し、累積的な負荷を見る。
このステップを踏むのが、最も安全で着実なチューニングロードマップです。
ログから何を読むか
ログに出力されたクエリを見ると、こんな情報が手に入ります。
2023-10-27 10:00:00.123 JST [1234] LOG: duration: 1540.231 ms statement:
SELECT FROM orders WHERE user_id = 5678 AND created_at > ‘2023-01-01’;
この一行から、僕たちは以下のことを読み解きます。
- duration: 1.5秒かかっている。これはユーザー体験を損なうレベルだ。
- statement: 実行されたSQL。WHERE句に注目。
- Index: `user_id` にインデックスは貼られているか? `created_at` との複合インデックスが必要か?
ここからは `EXPLAIN ANALYZE` の出番です。ログに出たSQLをコピーして、手元で実行計画を確認する。これがエンジニアの日常的な「探偵業務」ですね。
注意点:ログの海に溺れないために
最後に、一つだけ先輩からの忠告を。
`log_min_duration_statement` を有効にすると、ログが驚くほど速く溜まります。本番環境で運用する際は、以下の2点もセットで考えておいてください。
1. ログローテーションの設定: `log_rotation_age` や `log_rotation_size` で、ディスクを圧迫しないようにしておくこと。
2. ログの解析ツール: 溜まったログを眺めるのは修行です。`pgBadger` のようなログ解析ツールを使って、どのクエリがトップコストなのかを可視化する習慣をつけましょう。
—
まとめ
`log_min_duration_statement` は、PostgreSQLがあなたに送ってくれる「SOSの信号」です。これを放置するのは、せっかくの診断結果を見ないで医者をやっているようなもの。
まずは設定を一箇所変えて、ログを覗いてみてください。「あ、こんなところで全件検索してたのか!」といった発見が必ずあるはずです。
データベースのチューニングは地味ですが、確実にシステムの寿命を延ばし、ユーザーを笑顔にします。さあ、次はあなたの番ですよ。何か詰まったら、いつでも聞いてください。応援しています。
コメント