【実務・中級編】 Hashインデックスの特性とチューニング – PostgreSQL

やあ、今日もデータベースの深淵を覗きに来たね。

PostgreSQLのインデックスといえば、誰もが真っ先に「B-tree」を思い浮かべるはずだ。実際、ほとんどのケースでB-treeを選んでおけば間違いない。でもね、現場で長く戦っていると、「これ、本当にB-treeである必要ある?」と疑問に思う場面に出くわすことがある。

今日は、そんな時に選択肢に入ってくる「Hashインデックス」について、現場の視点から掘り下げてみようと思う。教科書通りの説明は他のサイトに任せて、ここでは「いつ使い、どこでハマるのか」という実戦的な話をしよう。

—

Hashインデックス:そのストイックな性格

Hashインデックスを一言で言うなら、「等価比較という一点にすべてを賭けたスペシャリスト」だ。

B-treeが「大小比較(範囲検索)」をこなせる万能選手なら、Hashは「=(イコール)」の検索において、その真価を発揮する。内部構造は単純だ。キー値をハッシュ関数に放り込み、得られたハッシュ値に基づいてバケットに振り分ける。

この構造の最大のメリットは、「検索の計算量がキーの長さに依存しにくい」という点にある。非常に長い文字列や、複雑なデータ型の等価比較を行うとき、B-treeだと深さが増してインデックス自体が肥大化しがちだけど、Hashならコンパクトに収まることが多いんだ。

なぜ普段使わないのか?

「じゃあ、等価比較なら全部Hashでいいじゃん」と思った君、鋭い。でも、現実はそう甘くない。

1. 範囲検索ができない
`WHERE id > 100` とか `WHERE created_at BETWEEN …` なんてクエリは、Hashインデックスでは門前払いだ。スキャンすらできない。
2. ソートできない
B-treeはインデックス自体がソートされているから、`ORDER BY`句が効く。Hashインデックスはバラバラに配置されるから、当然ソートなんて概念はない。
3. 歴史的な経緯(実は改善されている)
昔のPostgreSQLでは「HashインデックスはWALログに書き込まれないから、クラッシュしたらインデックスが壊れる」という重大な欠点があった。でも安心してほしい。PostgreSQL 10以降、この問題は完全に解消されて、今では非常に堅牢なインデックスになっている。

実践:どんな時にHashインデックスを使うべきか

僕がHashインデックスを検討するのは、主に「巨大なテーブルの、特定のカラムに対する完全一致検索」が頻発する時だ。

例えば、ユーザーのメールアドレスや、システム内で発行した一意なトークンなど。これらは範囲検索することがまずない。

— よくある「ユーザーのログイン認証」のようなケース
CREATE INDEX idx_user_email_hash ON users USING HASH (email);

こうすることで、B-treeを作るよりもインデックスサイズを小さく抑えられる可能性がある。インデックスサイズが小さければ、メモリ(shared_buffers)への載りも良くなる。結果として、I/O負荷が下がり、パフォーマンスが向上する……というのが理想的なシナリオだね。

チューニングの心得

Hashインデックスをいじる際に知っておいてほしいことが一つある。それは「フィルファクタ(fillfactor)」の設定だ。

Hashインデックスのバケットがいっぱいになると、データがオーバーフローしてしまい、検索効率がガクンと落ちる。デフォルト値は90だが、更新頻度が高いテーブルなら、もう少し余裕を持たせるのが賢いやり方だ。

— 更新が激しいなら fillfactor を下げてバケットの衝突を避ける
CREATE INDEX idx_user_email_hash ON users USING HASH (email) WITH (fillfactor = 70);

ただ、これも「最適解」はデータ量と更新頻度のバランス次第だ。`pg_stats`や`pg_opclass`を眺めながら、数値を調整する手間を惜しまないでほしい。

最後に:先輩からのアドバイス

結局のところ、Hashインデックスは「飛び道具」に近い。

「B-treeで十分速いなら、あえて変える必要はない」というのが僕の結論だ。Hashインデックスに切り替える前に、まずは`EXPLAIN ANALYZE`を叩いて、実行計画とI/Oのボトルネックを冷静に見極めてほしい。

もし、インデックスサイズが大きすぎてメモリに乗り切らず、どうしても等価検索を高速化したい……という壁にぶつかったら、その時はじめてHashインデックスというカードを切るのが、プロのエンジニアの作法だと思うよ。

さて、今日はここまで。データベースのチューニングに「絶対に正しい」という答えはない。常に環境とデータと対話して、納得いくまで検証を繰り返してくれ。それが一番の近道だ。

また何か気になったら、いつでも聞きに来てよ。

コメント

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