PostgreSQLの実行計画、無理やり「矯正」したくなるときあるよね?
現場でPostgreSQLをいじっていると、一度は経験するはずです。「なぜかインデックスを使わず、全件走査(Seq Scan)で突っ走ってしまうクエリ」や、「なぜかメモリを食いつぶすHash Joinを選択してくるクエリ」。
オプティマイザが「これが一番速いよ」と提示する実行計画が、実際には現場のデータ分布と噛み合わず、泥沼のようなクエリ遅延を引き起こすこと。これ、あるあるですよね。
そんな時、我々エンジニアの武器になるのが `enable_seqscan` をはじめとする「プランナ制御パラメータ」です。今日は、これらをどう扱うのが「現場の正解」なのか、僕の経験を交えてお話しします。
—
まずは「禁じ手」であることを理解する
いきなり結論から言いますが、これらのパラメータを本番環境の `postgresql.conf` で恒常的にオフにするのは「最終手段」であり、基本的にはアンチパターンです。
PostgreSQLのプランナは、統計情報をもとに「最もコストが低い」方法を計算しています。`enable_seqscan = off` なんて設定をしてしまうと、オプティマイザの判断能力をわざわざ奪っているのと同じ。将来的にデータ量が増えたとき、本来なら全件走査の方が速いケースまでインデックスを強制され、システム全体が悲鳴を上げることになります。
じゃあ、いつ使うのか? そう、「検証」と「緊急回避」です。
—
具体的な使い方:セッション単位で「強制」する
本番環境で全体に影響を与えず、特定のクエリだけをテストしたいなら、設定をセッションレベルで一時的に変更するのが鉄則です。
— トランザクションの中で一時的に制御する
BEGIN;
SET LOCAL enable_seqscan = off;
— ここで実行計画を確認したいクエリを流す
EXPLAIN ANALYZE SELECT FROM users WHERE status = ‘active’;
ROLLBACK;
こうすれば、他のユーザーやプロセスには一切影響を与えずに、「もしSeq Scanじゃなかったらどれくらい速いのか?」を検証できます。
—
よく使うパラメータと僕の使い分け
現場でよく触る主要なパラメータを整理しておきます。
- `enable_seqscan`: 全件走査を禁止する。インデックスが効くはずなのにフルスキャンしている時に「インデックスは本当に速いのか?」を確認するのに使います。
- `enable_indexscan` / `enable_indexonlyscan`: 逆にあえてインデックスを使わせない時に。統計情報のズレで、無駄なインデックスアクセスが頻発している時の切り分けに使います。
- `enable_hashjoin` / `enable_mergejoin`: 結合アルゴリズムの制御。Nested Loopで叩いた方が速いケースを見極めたい時に重宝します。
—
「なぜ」選ばれないのかを考えるのがエンジニアの仕事
パラメータをいじって「お、速くなった!」で終わらせないでください。それはただの鎮痛剤です。
プランナが誤った選択をするのには、必ず理由があります。
1. 統計情報が古い: `ANALYZE` を実行したら解決した、なんてのは序の口です。
2. データの偏り: 特定のステータスにデータが集中していて、プランナが「これなら全件走査の方が早い」と判断している。
3. 相関関係の考慮漏れ: 複数のカラム条件(例:`pref = ‘tokyo’` かつ `city = ‘shinjuku’`)が組み合わさっている時、プランナがそれぞれの選択率を単純に掛け算して、実際より過小評価している。
これらを突き止めるのが、データベースエンジニアとしての腕の見せ所です。
—
最後に:先輩からのアドバイス
もし、どうしても実行計画を制御したい状況に陥ったら、`enable_…` パラメータで無理やり固定する前に、まずは以下の3つを試してみてください。
- `EXPLAIN (ANALYZE, BUFFERS)` を見る: どこで時間がかかっているのか、実際のコストと見積もりの乖離を確認する。
- 統計情報の更新: `ANALYZE` をかけて、それでもダメなら `ALTER TABLE … ALTER COLUMN … SET STATISTICS` で統計情報の精度を上げる。
- インデックスの再考: 複合インデックスを貼る、あるいは `WHERE` 句の書き方を工夫してプランナを誘導する。
これでもダメな時の「最後の切り札」として、今日のテクニックを思い出してください。道具は、使う場所とタイミングで「薬」にも「劇薬」にもなります。
現場のDBが快適に動くよう、ぜひ賢く使いこなしてみてくださいね。応援しています!
コメント