インデックスが太る夜に。PostgreSQLの「肥大化」と戦うためのREINDEX戦略
PostgreSQLを長く運用していると、ふと気づく瞬間があるはずだ。クエリの実行計画を確認すると、明らかにデータ量に対してインデックスのサイズが肥大化している。`pgstattuple`で覗いてみれば、案の定、断片化(bloat)率が目を覆うような数値になっている。「また君か」と溜息をつきつつ、我々DBAはメンテナンスの計画を立てることになる。
今日は、そんなPostgreSQLのインデックス肥大化問題と、その特効薬である`REINDEX`について、少し深い話をしよう。
なぜインデックスは「太る」のか
まず、根本的な原因を整理しておこう。PostgreSQLのMVCC(多版同時実行制御)アーキテクチャでは、更新処理は「古い行の削除」と「新しい行の挿入」の組み合わせで行われる。
インデックス側も同様だ。行が更新されるたびに、古いエントリを無効化し、新しいエントリを追加する。もし`FILLFACTOR`の調整を怠り、かつ更新頻度が高いテーブルであれば、インデックスページ内に空き領域(デッドタプル)が蓄積され、木構造はスカスカになり、検索効率は当然のごとく低下する。
特に、ランダムなキーに対する頻繁な更新や削除が発生する環境では、この「肥大化」は避けて通れない宿命のようなものだ。
REINDEX CONCURRENTLY という福音
かつて、インデックスの再構築といえば、テーブルをロックして書き込みを停止させる必要があった。しかし、24時間365日の稼働が求められる現代のシステムで、そんな荒業は許されない。
そこで登場するのが `REINDEX INDEX CONCURRENTLY` だ。
このコマンドの素晴らしい点は、テーブルに対する共有ロック(`SHARE UPDATE EXCLUSIVE`)のみを取得し、読み書きを妨げずに裏側で新しいインデックスを作成する点にある。手順はこうだ:
1. 新しいインデックスを並行して作成する。
2. 既存のインデックスと新しいインデックスの両方へ更新を反映させる。
3. 新しいインデックスが完成したら、古いものと差し替える。
一見完璧に見えるが、注意点もいくつかある。
- 実行時間の長期化: 処理負荷を抑えるために非ロックで実行するため、通常の`REINDEX`よりも完了までに時間がかかる。
- 一時的なディスク消費: 既存インデックスと同等のサイズが一時的に確保されるため、ディスク容量には余裕を持たせておく必要がある。
- 失敗時の残骸: もし何らかの理由(デッドロックやディスクフルなど)で中断された場合、`INVALID`状態のインデックスが残る。これは手動で削除する必要がある。
現場でのベストプラクティス:いつ「再構築」すべきか
闇雲に`REINDEX`を打つのは、実は得策ではない。インデックスの再構築は、I/Oを激しく消費する重い処理だ。私は以下の基準で判断している。
1. pgstattupleによる客観的評価:
`pgstattuple`拡張を使って、`free_space`や`dead_tuple_percent`を確認する。なんとなく「遅い気がする」という直感ではなく、数値で判断すること。
2. FILLFACTORの再考:
もしインデックスが頻繁に肥大化するなら、そもそも`FILLFACTOR`がデフォルトの100のままではないか疑うべきだ。更新が多いテーブルなら、80〜90程度に下げておくことで、ページ内の「余白」を確保し、断片化の速度を劇的に遅らせることができる。
3. VACUUMの効き具合:
`autovacuum`が適切に動いていれば、ある程度の空き領域は再利用される。まずは`autovacuum`のチューニング(`autovacuum_vacuum_scale_factor`や`autovacuum_vacuum_cost_limit`)が適正かを見直すのが先決だ。`REINDEX`はその最後の手段であるべきだ。
最後に:メンテナンスも「設計」の一部
DBAという仕事をしていると、「インデックスを貼る」ことには情熱を注ぐのに、「インデックスを捨てる、あるいは整える」ことには無頓着なケースによく出くわす。
しかし、ストレージのレイテンシやキャッシュヒット率を考慮したとき、インデックスの健全性を保つことは、SQLを最適化するのと同じくらい重要だ。
`REINDEX CONCURRENTLY`は、我々に「止まらないシステム」を維持しながら、バックエンドの健康を保つ強力な武器を与えてくれた。ぜひ、自身の環境のインデックスサイズを一度見直してみてほしい。驚くほど無駄な領域が、あなたのデータベースの中に眠っているかもしれない。
さて、そろそろバキュームの実行計画でも眺めるとしようか。諸君のデータベースが、今日も軽快に動くことを願っている。
コメント