「データベースのパフォーマンスが突然落ちた……」
そんな時、原因の多くは「断片化(Bloat)」です。特にUPDATEが頻繁に走るテーブルでは、PostgreSQLのMVCC(多版同時実行制御)の特性上、どうしても避けられない問題ですよね。
今日は、そんな悩みを抱えるエンジニアの皆さんに、「FILLFACTOR(フィルファクタ)」という、現場で「ここぞ!」という時に使う裏技的な設定を紹介したいと思います。教科書には載っているけれど、意外と調整の仕方が分からない……そんな設定を、実戦的な視点で深掘りしていきます。
—
FILLFACTORって、そもそも何者?
簡単に言うと、「データページにどれだけデータを詰め込むか」を決めるパーセンテージです。
PostgreSQLは通常、データページ(デフォルトで8KB)を限界まで埋めようとします(FILLFACTOR 100%)。しかし、もし「更新」が頻繁に発生するテーブルだったらどうでしょう?
PostgreSQLのUPDATEは、実は「古いレコードを消して、新しいレコードを書き込む」という動きをします。もしページがパンパンに詰まっていたら、新しいデータは別のページに書き込まれることになりますよね。これが断片化の始まりです。
なぜFILLFACTORを下げるのか?
答えはシンプル。「余白」を作るためです。
ページ内にあえて空きスペースを作っておけば、更新された新しいレコードを「同じページ内」に書き込める可能性が高まります。これがPostgreSQLの強力な武器である「HOT(Heap Only Tuple)更新」を誘発する鍵なんです。
HOT更新ができると、インデックスの更新コストがゼロになります。これはパフォーマンスにおいて天と地ほどの差が出ます。
—
実践:FILLFACTORを調整するタイミング
では、具体的にどう設定すればいいのか。まずはテーブルの現状を確認しましょう。
— テーブルのFILLFACTORを確認
SELECT relname, reloptions
FROM pg_class
WHERE relname = ‘your_table_name’;
もし`reloptions`が空なら、デフォルトの100が適用されています。
設定のコード例
更新頻度が高いテーブルであれば、まずは「90」あたりから試してみるのが鉄則です。
— テーブルのFILLFACTORを90に変更
ALTER TABLE your_table_name SET (fillfactor = 90);
— 変更後は必ずVACUUM FULL、あるいはテーブルの再作成が必要
— (ALTER TABLEだけでは既存データには適用されません)
VACUUM FULL your_table_name;
※注意点ですが、`VACUUM FULL`はテーブルをロックするので、本番環境では注意してくださいね。最近の現場では、`pg_repack`などのツールを使ってオンラインで適用するのが一般的です。
—
どのくらい「下げれば」いいの?
ここが一番の悩みどころですよね。結論から言うと、「銀の弾丸はない」です。
- 更新が極めて多いテーブル: 70〜80%
- 一般的な更新頻度: 90%
- INSERTオンリー(マスターデータ等): 100%(デフォルトでOK)
「空きスペースを増やせば増やすほど、検索効率は落ちる(ページ数が増えるのでディスクI/Oが増える)」というトレードオフがあることを忘れないでください。
私の経験則では、まずは90%に設定して、`pg_stat_user_tables` の `n_tup_upd` (更新数)と `n_tup_hot_upd` (HOT更新数)の比率を観察します。HOT更新の割合が低いなら、もう少し下げて余白を広げる、といった調整が現実的なアプローチです。
—
先輩からのアドバイス
「FILLFACTORをいじれば全て解決する」なんて魔法ではありません。一番大事なのは、「自分のアプリケーションがどの程度更新を行うのか」を正しく把握することです。
インデックスに対してもFILLFACTORは設定できます。インデックスの更新が重い場合は、インデックス側にも90%程度の設定を検討してみてください。
データベースのチューニングは、顕微鏡で細胞を見るような地道な作業ですが、ここをいじれるようになると、システム全体の挙動をコントロールしている実感が湧いてくるはずです。
もし「最近、VACUUMの頻度が高すぎて困っている」「更新処理が重い」と感じているなら、ぜひFILLFACTORをチェックしてみてください。きっと、目に見える変化があるはずですよ。
それでは、また次回の記事でお会いしましょう!
コメント