「遅い…」を解決する第一歩。PostgreSQLの `maintenance_work_mem` を使いこなそう
現場でPostgreSQLを触っていると、必ず一度は壁にぶつかるのが「メンテナンス処理の重さ」です。「インデックス作成に何時間もかかる」「VACUUMがちっとも終わらない」……そんな時、パラメータをいじって劇的に改善した経験、あなたにはありますか?
今日は、そんな現場の駆け込み寺的パラメータ、`maintenance_work_mem` について話をしましょう。教科書的な定義をなぞるだけじゃなく、「結局どう設定すればいいの?」という実践的な勘所を共有しますね。
—
`maintenance_work_mem` って、何者?
簡単に言うと、これは「メンテナンス作業専用の作業用メモリ」です。
PostgreSQLは、データ読み書き用のメモリ(`shared_buffers`など)とは別に、インデックスの作成(`CREATE INDEX`)や、`VACUUM`、`ALTER TABLE`といった「裏方の仕事」のためにメモリを確保します。その上限を決めているのがこの設定です。
デフォルト値は64MB。正直に言います。今の時代、この設定のまま運用していると、DBのポテンシャルをかなり殺している可能性が高いです。
なぜこのメモリが重要なのか
インデックス作成時を例に考えてみましょう。PostgreSQLはデータを並べ替えてインデックスを作るわけですが、この時メモリが足りないとどうなるか。
1. メモリに収まらない分をディスク(一時ファイル)に書き出す。
2. ディスクから読み直して再計算する。
3. また書き出す……。
……想像するだけで遅そうですよね。ディスクI/Oはメモリの数千倍遅いです。`maintenance_work_mem` を十分に割り当てておけば、この「ディスクへの退避」を抑え込み、メモリ上で高速にインデックスを構築できるんです。
実践的な設定の勘所
じゃあ、どれくらい設定すればいいの? という話ですよね。
結論から言うと、「システムに余裕があるなら、1GB〜数GB程度まで大胆に振る」のが僕の推奨です。
ただ、注意点がひとつ。この設定は「セッションごとに割り当てられる」という点です。もし同時に複数のインデックス作成コマンドを走らせるなら、その数だけメモリを食います。
設定を確認・変更するコマンド
まずは現在の値を見てみましょう。
SHOW maintenance_work_mem;
変更は、本番環境なら `postgresql.conf` を書き換えて再読み込み(`pg_ctl reload`)するのが基本ですね。
— 一時的に特定のセッションだけで大きくしたい場合(インデックス作成直前など)
SET maintenance_work_mem = ‘2GB’;
CREATE INDEX CONCURRENTLY idx_huge_table_col ON huge_table(column_name);
注意!「魔法の杖」ではない
ここで一つ、現場の先輩として釘を刺しておきたいことがあります。「大きくすればするほど速くなるわけではない」ということです。
ある一定のラインを超えると、それ以上メモリを積んでも劇的な効果は現れなくなります。また、サーバー全体の空きメモリがカツカツの状態でこれを大きくしすぎると、OSがメモリ不足(OOM Killer)を起こしてPostgreSQLごと落とされてしまう……なんて笑えない事故も起こり得ます。
- 小〜中規模DBなら: 256MB〜512MB
- 大規模かつメモリ潤沢なサーバーなら: 1GB〜4GB程度
まずはこのあたりから始めて、`EXPLAIN ANALYZE` や `pg_stat_statements` で処理時間を見て調整していくのが王道です。
まとめ:現場で意識してほしいこと
`maintenance_work_mem` は、いわば「DBの大掃除を快適にするための体力」です。
- `CREATE INDEX` が遅いと感じたら、まずこの値を疑うこと。
- 大量の `VACUUM` が走る夜間バッチがあるなら、その時だけ値を大きくする工夫を検討すること。
- サーバーのメモリ総量と、同時実行数を忘れないこと。
インデックス作成の数時間が数分に短縮されたとき、その爽快感はエンジニア冥利に尽きるはずです。ぜひ、自分の環境でチューニングを試してみてください。
何か分からないことがあれば、またいつでも聞きに来てくださいね。現場からは以上です!
コメント