Spannerのセカンダリインデックス:その「見えない代償」と最適解を語る
Cloud Spannerを触り始めたエンジニアが、まず最初に突き当たる壁。それが「インデックス設計」だ。RDBMSの感覚で安易にインデックスを貼ると、Spannerの分散アーキテクチャという名の「現実」に即座に殴られることになる。
今日は、Spannerにおけるセカンダリインデックスの深淵について、設計レビューの現場で私が必ず指摘するポイントを紐解いていく。
—
1. セカンダリインデックスは「別のテーブル」であるという事実
まず、胸に刻んでほしい。Spannerにおいてインデックスは、実テーブルとは別個に管理される「隠れたテーブル」である。
- インデックスを作成すると、そのデータは独立して分割(Split)され、ノード間で分散配置される。
- 書き込み(INSERT/UPDATE/DELETE)のたびに、その裏側で自動的にインデックス更新のトランザクションが走る。
これが何を意味するか? インデックスを1つ増やすたびに、書き込みのスループットは低下し、ストレージコストは増加する。 「検索が遅いから」といって無秩序にインデックスを貼る行為は、システム全体の寿命を縮めているのと同じだ。
2. NULL値とインデックスの「静かなる罠」
Spannerのインデックスにおいて、NULL値の扱いは非常に賢い。
「NULL値は、デフォルトでインデックスエントリとして格納されない」
これはストレージ効率の観点では素晴らしいが、検索時には注意が必要だ。例えば `WHERE column IS NULL` というクエリを投げた際、インデックスがその列のNULLを保持していない場合、オプティマイザはインデックスを無視してフルスキャンを選択する可能性がある。
- 設計のヒント: 特定のフラグ(例:`is_deleted`)でNULLを活用する場合、インデックスの「格納される性質」を理解しておくこと。もしNULLを頻繁に検索対象にするなら、あえて `NULL` ではなくデフォルト値(`0` や `false`)で埋める設計の方が、実行計画は安定する。
3. 「STORING」句を使いこなせ:パフォーマンスの劇薬
インデックスの真骨頂は、`STORING` 句にある。これを使えば、インデックス内に実テーブルの列をコピーして持たせることができる。
— よくある例:ユーザーのメールアドレスで検索し、名前も取得したい
CREATE INDEX UsersByEmail ON Users(Email) STORING (Name);
このインデックスを使えば、Spannerは実テーブルを読みに行く(Key Lookup)必要がない。「インデックスのみの読み取り(Index Only Scan)」が完成する。
ただし、ここにも罠がある。 `STORING` で指定した列が更新されるたびに、そのインデックスも更新される。読み取り性能を稼ぐために書き込み性能を削る、このトレードオフを論理的に説明できないのであれば、その設計は未熟だ。
4. インデックスの断片化とキー設計
Spannerはキーの先頭から順序付けを行う。もし、インデックスの先頭列に「単調増加する値(タイムスタンプなど)」を置くとどうなるか。
そのインデックスは、特定のノードに書き込みが集中する「ホットスポット」を生む。これがSpannerの性能を殺す最大の要因の一つだ。
- 対策: インデックスのキー順序を工夫するか、あるいは `HASH` インデックスの利用を検討せよ。単なるB-Tree的なインデックス作成ではなく、分散アーキテクチャを意識したキー設計こそが、チーフアーキテクトの仕事だ。
5. 現場のアーキテクトからの提言
最後に、設計レビューで私が伝えている「鉄則」をまとめておく。
1. 「とりあえず貼る」は禁止: インデックスは「必要最小限」が原則。スロークエリログを見て、本当に必要なものだけを後から追加せよ。
2. `STORING` は魔法ではない: インデックスの肥大化と引き換えに、実テーブルへのラウンドトリップを減らすトレードオフを常に計算せよ。
3. 実行計画(Query Plan)を愛せ: `EXPLAIN ANALYZE` を実行しないエンジニアにSpannerを触らせてはならない。インデックスが本当に使われているか、Table Scanが走っていないか、その目で確認せよ。
4. 結合(Join)への意識: インデックスを適切に配置することで、Nested Loop Joinの効率は劇的に変わる。クエリの構造に合わせてインデックスを最適化せよ。
—
Spannerは、ただの「マネージドなRDBMS」ではない。分散システムの複雑さを隠蔽しつつ、我々エンジニアに「分散環境におけるデータ構造の最適化」という難問を突きつけてくる洗練されたプラットフォームだ。
インデックスの1行、クエリの1文字。その積み重ねが、数年後のスケーラビリティを決定づける。今日から、インデックスを「性能向上のツール」ではなく、「システム全体との対話」として捉えてほしい。
健闘を祈る。
コメント