「なあ、最近PostgreSQLのログ見てるか?」
そう聞くと、たいていの若手は「エラーログですか? 特に何も……」と答えるんだ。でも、DBエンジニアとして一段上のステージに上がるなら、エラーログじゃなくて「パフォーマンスログ」の裏側にある設定、特に `maintenance_work_mem` に目を向けてほしいんだよね。
今日は、地味だけど実は破壊力抜群なこの設定について、現場の知見を少し共有するよ。
—
`maintenance_work_mem` って結局なんなの?
一言で言えば、「DBのお掃除や準備運動に使える専用のメモリ領域」だ。
`work_mem` がクエリのソートや結合に使う「作業机」なら、`maintenance_work_mem` は `VACUUM` や `CREATE INDEX`、`ALTER TABLE` といった、テーブルをメンテナンスするための「工具箱」みたいなものだと思ってくれ。
デフォルト値は64MB。これ、今の時代だと正直「お話にならない」レベルで小さいんだ。数百GBのテーブルを抱えている環境で64MBの工具箱を開いたら、VACUUMなんて終わるはずがないよね。
なぜこの設定が重要なのか?
理由はシンプル。「メンテナンスの速度」と「システムへの影響」が、この値でガラッと変わるからだよ。
例えば、`VACUUM` を実行するとき、PostgreSQLはテーブルの中の「不要になった行(デッドタプル)」の場所をメモしておく必要がある。このメモ帳が `maintenance_work_mem` だ。
- 値が小さいと: メモ帳がすぐ溢れる。溢れるとどうなるか? テーブルを何度もスキャンし直すことになる。結果、VACUUMが終わらない、I/Oが跳ね上がる、システム全体が重くなるという地獄のループに入るわけだ。
- 値が大きいと: メモ帳に余裕があるから、少ないスキャン回数で効率よくゴミ掃除ができる。インデックス作成も、メモリ上で高速にソートできるから劇的に速くなる。
実務で意識すべき「さじ加減」
じゃあ、「メモリをたくさん積めばいいんでしょ? 16GBくらい割り当てちゃえ!」って言いたくなるかもしれないけど、ちょっと待って。
`maintenance_work_mem` は「メンテナンス処理ごと」に消費される。もし並列で複数のインデックス作成を走らせたら、その分だけメモリを食うんだ。サーバーの空きメモリを考慮せずに欲張ると、最悪の場合、OSのOOM Killerにプロセスを強制終了させられるよ。
僕が現場で推奨している目安
1. デフォルトのまま放置は厳禁: 最低でも 256MB〜1GB くらいには引き上げておこう。
2. 物理メモリの比率で考える: サーバー全体のメモリの 5%〜10% 程度を上限の目安にするのが安全かな。
3. 一時的な調整: 大規模なインデックス作成や、データの入れ替えなど、重い作業をする時だけセッション単位で大きくするのもアリだ。
— セッション単位で一時的に拡張する例
— インデックス作成を高速化したいときだけ広げる
SET maintenance_work_mem = ‘2GB’;
— その後、インデックスを作成
CREATE INDEX CONCURRENTLY idx_users_created_at ON users(created_at);
実践的なアドバイス:VACUUMのログを見ろ
「自分の環境の `maintenance_work_mem` が適切かどうか」を判断する一番確実な方法は、ログを確認することだ。`autovacuum` が実行された後にログを漁ってみてくれ。
「`index scans not needed`」とか「`buffer usage`」といったキーワードが出てくるはずだ。もし、`VACUUM` が何度も何度も繰り返しスキャンしているようなら、それは間違いなく `maintenance_work_mem` が足りていないサインだと思っていい。
まとめ
`maintenance_work_mem` は、PostgreSQLの「健康維持」のための命綱だ。
- デフォルト値は現代のサーバーには小さすぎる。
- メモリの余裕を見て適切に増やすことで、メンテナンス時間を劇的に短縮できる。
- ただし、並列実行時のメモリ枯渇には注意する。
DBの運用って、派手なクエリチューニングも大切だけど、こういう「基盤の土台」をしっかり整える作業の積み重ねなんだよね。ここを調整するだけで、夜間のバッチ処理が数時間早まることも珍しくない。
まずは今度、自分の担当しているDBの設定値を確認してみて。もし64MBのままなら、今日が改善のチャンスだよ!
また何か詰まったら、いつでも聞きに来てくれ。
コメント