【テクニカル・上級編】 インデックスの肥大化(Bloat)と対策 – PostgreSQL

インデックスの「肥大化」と静かに戦う夜:PostgreSQLのBloatを制御する

PostgreSQLの運用を長く続けていると、必ず一度は直面する壁がある。テーブルの行数やトラフィックは変わっていないはずなのに、なぜかインデックスのサイズだけが右肩上がりに増え続け、クエリのレスポンスが微妙に悪化していく――いわゆる「インデックスの肥大化(Bloat)」だ。

今日は、この目に見えない「負債」をどう検知し、どのようにスマートに解消すべきか、現場のエンジニア同士の知見として共有したいと思う。

—

なぜインデックスは「太る」のか

PostgreSQLのMVCC(多版同時実行制御)アーキテクチャを理解していれば、この現象の正体はすぐに掴めるだろう。

PostgreSQLのインデックスは、テーブルの更新(UPDATE)が走るたびに、古いタプルを指すエントリを残したまま、新しいタプルのためのインデックスエントリを作成する。もちろん、`VACUUM`が不要になった領域を再利用しようと努力はしてくれる。しかし、HOT(Heap Only Tuple)更新が効かないケースや、ページ内での再利用が追いつかないような更新頻度の高いカラムでは、インデックスページ内に「空の隙間」がどんどん溜まっていく。

これが肥大化の正体だ。物理的なインデックスサイズが大きくなれば、メモリ上のバッファキャッシュを圧迫し、結果としてB-treeの深さが増し、I/O負荷が跳ね上がる。まさに「百害あって一利なし」の状況だ。

—

現場での検知:直感ではなく数値を信じる

「なんとなくインデックスが肥大している気がする」といった感覚は危険だ。まずは客観的な指標を見よう。私は普段、`pgstattuple`拡張を使っている。

CREATE EXTENSION IF NOT EXISTS pgstattuple;

— 特定のインデックスの状況を確認
SELECT FROM pgstatindex(‘your_index_name’);

ここで重要なのは `avg_leaf_density`(リーフページの充填率)だ。これが極端に低い(例えば50%を切るような)場合、そのインデックスは明らかに「スカスカ」の状態だと言える。これを定期的に監視し、しきい値を設けてアラートを飛ばすのが、熟練の運用というものだ。

—

対策:REINDEXか、それとも「魔法」か

肥大化を解消する方法はいくつかあるが、状況に応じて使い分けるのがプロの流儀だ。

1. REINDEX CONCURRENTLY(推奨)

PostgreSQL 12以降、これは神ツールとなった。`REINDEX CONCURRENTLY`を使えば、インデックス構築中にテーブルをロックすることなく、クエリ処理を阻害せずにインデックスを再構築できる。

REINDEX INDEX CONCURRENTLY your_index_name;

昔は「運用中にインデックスを張り替えるなんて…」と胃を痛めたものだが、今は安心して夜を越せる。ただし、システム負荷はそれなりにかかるので、オートバキュームが走っていない時間帯を見計らうのが鉄則だ。

2. VACUUM(対症療法)

`VACUUM`は、あくまで「空いた隙間を再利用可能にする」だけであり、物理的なインデックスサイズを縮小してくれるわけではない。インデックスの肥大化が深刻な場合、`VACUUM`をいくら叩いても焼け石に水だ。これはあくまで日々の予防メンテとして捉えるべきだ。

3. FILLFACTORの調整(予防戦略)

もし更新頻度が極めて高いことが分かっているなら、インデックス作成時に `FILLFACTOR` を少し下げておくのも手だ。

CREATE INDEX idx_your_column ON your_table(column) WITH (FILLFACTOR = 80);

こうすることで、ページ内にあえて「余白」を作り、HOT更新やページ内での更新を効率化できる。ただし、インデックス全体のサイズは最初から大きくなる。パフォーマンスと肥大化のトレードオフを計算し、あえて「最初から太らせておく」という戦略的判断が必要だ。

—

最後に:完璧なシステムはない

データベースエンジニアとして一つ言えるのは、「肥大化をゼロにすることは不可能」だということだ。これはPostgreSQLの設計思想と引き換えに得ているコストだからだ。

大切なのは、肥大化が「起きること」を前提に、それを定常的に観測し、システムに負荷をかけない方法で計画的にメンテナンスを行う運用体制を作ることだ。

「最近、なんとなくクエリが重いな」と感じたとき、あなたはディスクの空き容量だけでなく、インデックスの中身の「密度」に思いを馳せているだろうか。そうやってデータベースの深淵を覗き込めるエンジニアが、結局のところ、一番安定したシステムを構築できるのだと思う。

皆さんのインデックスが、今日も健やかであることを祈っている。

コメント

タイトルとURLをコピーしました