【実務・中級編】 REINDEXコマンド – PostgreSQL

インデックスの「健康診断」、ちゃんとやってる?REINDEXでPostgreSQLをリフレッシュしよう

やあ。最近、データベースのパフォーマンスチューニングに追われてないかな?
「以前はサクサク動いていたクエリが、最近なんだか重い気がする……」
「実行計画を見ても、インデックスは効いているはずなのにレスポンスが悪い」

そんな悩みを抱えているなら、一度インデックスの「肥大化(Bloat)」を疑ってみるべきだ。今日は、PostgreSQLの運用で避けては通れない、インデックス再構築コマンド『REINDEX』の話をしようと思う。

—

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

まず前提として、PostgreSQLのMVCC(多版同時実行制御)の仕組みを思い出してほしい。
PostgreSQLでは、データ(行)を更新すると、実際には「古い行を無効にして、新しい行を別の場所に書き込む」という挙動をする。

これと同じことが、インデックスにも起きるんだ。インデックスのツリー構造の中で更新や削除が繰り返されると、使われなくなった領域が「デッドスペース」としてインデックス内に残ってしまう。これをインデックスの肥大化(Bloat)と呼ぶ。

肥大化すると何が起きるか?
1. スキャン効率の低下: 無駄な空間を読み込むために、I/Oが増える。
2. キャッシュ効率の低下: メモリ(shared_buffers)に載る有効なインデックス情報の密度が下がる。

結果として、クエリは遅くなり、ディスク容量も無駄に食うことになる。これを解消するのが`REINDEX`の役割だ。

—

基本のREINDEXコマンド

まずは基本の書き方だ。一番シンプルなのはテーブル単位での実行だね。

— 特定のテーブルの全インデックスを再構築
REINDEX TABLE users;

もし、特定のインデックスだけが極端に肥大化しているなら、それ単体で叩くこともできる。

— 特定のインデックスのみ再構築
REINDEX INDEX users_email_idx;

—

実務で一番大切な「CONCURRENTLY」の話

さて、ここからが現場の先輩からのアドバイスだ。
本番環境で上のコマンドをそのまま叩くと、対象のテーブルに排他ロック(ACCESS EXCLUSIVE)がかかってしまう。 つまり、再構築が終わるまで、そのテーブルへの読み書きが完全に止まってしまうんだ。

サービス停止が許されないシステムでこれをやると、間違いなく朝会で謝罪することになる(笑)。

そこで登場するのが `CONCURRENTLY` オプションだ。

— 本番環境の鉄則
REINDEX TABLE CONCURRENTLY users;

これを使うと、テーブルをロックせずにインデックスを裏側で作り直してくれる。時間はかかるし、CPUやI/O負荷は上がるけれど、サービスを止めずに済む。実務では「REINDEXといえばCONCURRENTLY」と体に叩き込んでおこう。

—

実行のタイミングはどう判断する?

「よし、じゃあ毎日REINDEXしよう!」と思ったそこの君、ちょっと待って。
インデックス再構築は決して軽い処理じゃない。むやみに実行すれば、逆にパフォーマンスを悪化させることもある。

目安としては、`pgstattuple` 拡張を使って「インデックスの空き率」を計測するのがおすすめだ。

— pgstattupleのインストール(一度だけ)
CREATE EXTENSION pgstattuple;

— インデックスの統計を確認
SELECT FROM pgstatindex(‘users_email_idx’);

ここで `avg_leaf_density`(リーフページの密度)が極端に低い(例えば50%以下など)場合は、再構築を検討する価値がある。

—

先輩からの教訓:運用のアドバイス

最後に、現場で戦う君たちにいくつかアドバイスを。

  • 自動化は慎重に: 定期的な自動実行(cron等)は楽だけど、テーブルサイズが巨大になると再構築がいつ終わるか分からなくなる。まずは「重いな」と感じた時の手動メンテから始めて、必要に応じてスクリプト化するのが安全だ。
  • VACUUMとの違い: `VACUUM`はデッドタプルを掃除して領域を再利用可能にするが、一度膨らんだインデックスの構造そのものを「作り直して引き締める」ことはできない。だからこそ、`REINDEX`が必要なんだ。
  • ディスク容量に注意: `CONCURRENTLY`で実行している間は、新しいインデックスが完全に構築されるまで、古いインデックスと新しいインデックスが両方存在する。一時的にディスク容量を食うから、容量ギリギリのサーバーで実行する時は要注意だぞ。

データベースは、一度構築して終わりじゃない。こういう地味なメンテナンスを積み重ねていくことで、システムは長く、元気に動き続けてくれる。

もし「最近パフォーマンスが……」と頭を抱えていたら、まずはインデックスの状態を確認してみよう。意外と、REINDEX一発で劇的に軽くなることもあるからね。

それじゃ、また現場で会おう。健闘を祈る!

コメント

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