Cloud Spannerのスキーマ設計:分散データベースの深淵を制御する「物理的整合性」の追求
多くのエンジニアがCloud Spannerを「ただのスケールするRDBMS」と誤解している。だが、真のアーキテクトは理解しているはずだ。Spannerは分散システムであり、そのスキーマ設計とは、「データの物理的局所性と、分散トランザクションのオーバーヘッドを、SQLの抽象化層でいかに制御するか」という極限のパズルであることを。
本稿では、一般的な型定義の解説は飛ばす。Spannerの内部エンジン「Colossus」と「Spannerノード」の挙動を前提とした、設計の深淵に触れる。
—
1. プライマリキー:分散の「境界線」を支配する
Spannerにおいて、プライマリキー(PK)は単なるインデックスではない。それはデータの「分割(Split)」の単位を決定する指針だ。
- 単調増加キーのアンチパターンを再考する:
UUIDではなく`SEQUENCE`やタイムスタンプをPKにすると、特定のSplitに書き込みが集中する「ホットスポット」が発生する。これは常識だ。しかし、解決策として「UUID」を使うのも安直すぎる。UUIDはランダムすぎて、範囲スキャン(Range Scan)の効率を物理的に破壊する。
- 極限の知見: 適切なハッシュプレフィックスを付与し、かつスキャン特性を維持する「ビット反転」や「シャードIDの付与」を検討せよ。データアクセスパターンとスプリットの境界を、物理設計レベルで一致させるのがアーキテクトの腕の見せ所だ。
2. データ型がメモリ消費に与える「静かなる衝撃」
Spannerの列データ型は、単なるバリデーションではない。内部のストレージエンジンにおける圧縮率と、検索パフォーマンスを決定づける。
- STRING vs BYTES:
`STRING`はUTF-8エンコーディングを伴う。これは検索時に正規化コストがかかる。もしデータが不変であり、かつ照合が必要ないバイナリデータであれば、迷わず`BYTES`を選択せよ。
- NUMERICの罠:
`NUMERIC`型は高精度だが、計算コストは`FLOAT64`より高い。金融系の決済基盤であれば必須だが、そうでなければ、スケールと計算速度を優先するために`INT64`(最小単位に換算)を用いるのが、レイテンシを極限まで削る設計だ。
- ARRAY型のメモリ効率:
`ARRAY
3. スキーマ設計における「インターリーブ」の物理的必然性
テーブルを`INTERLEAVE IN PARENT`で階層化する最大の利点は、論理的な親子の紐付けではない。「物理的に同一のSplitに配置すること」にある。
— 親テーブル
CREATE TABLE Users (
UserId INT64 NOT NULL,
…
) PRIMARY KEY (UserId);
— 子テーブル:UsersのSplit内に物理的に格納される
CREATE TABLE UserSettings (
UserId INT64 NOT NULL,
SettingId INT64 NOT NULL,
…
) PRIMARY KEY (UserId, SettingId),
INTERLEAVE IN PARENT Users ON DELETE CASCADE;
- 内部メカニズム:
インターリーブにより、親と子のデータが同じ物理ノード上の同一のキー範囲に保存される。これにより、JOINのコストは「ネットワークを跨ぐ分散結合」から「ローカルメモリ上のポインタ参照」へと劇的に進化する。これがSpannerが大規模データでも爆速である理由の半分だ。残りの半分は、Paxosによる分散合意の最適化である。
4. JSON型という劇薬
近年のアップデートで導入された`JSON`型。これを使えばスキーマレスな柔軟性が手に入る。しかし、これを「RDBの柔軟性不足を補うゴミ箱」にしてはならない。
- アーキテクトの視点:
Spannerの`JSON`型は内部的にバイナリ形式(`JSONB`に近い)で保持されるが、インデックスを貼る際のコストは通常の列とは異なる。特に、JSON内の深いパスに対してインデックスを貼る場合、クエリの実行計画が複雑化し、オプティマイザが迷子になるケースがある。
- 鉄則: 頻繁に更新・参照される値は、必ずトップレベルの`NUMERIC`や`STRING`列として切り出せ。JSON型は「メタデータ」や「将来の拡張性を担保するためのバッファ」として扱うのが、システムの長寿を保つコツだ。
—
結び:エンジニアは「データ」そのものを見るべきだ
Cloud Spannerは魔法の箱ではない。データがどこに配置され、どのようにPaxosグループ間を移動し、Colossus上でどう圧縮されているか。その物理的な挙動を理解した上でスキーマを定義する時、初めてパフォーマンスは「制御可能」なものとなる。
「とりあえずこの型でいいや」という妥協が、数年後の数千万リクエストを捌くシステムで「レイテンシの壁」として跳ね返ってくる。
スキーマを定義するその指先で、数年後のアーキテクチャの未来を設計してほしい。我々に必要なのは、仕様書の遵守ではなく、物理層への畏怖と理解に基づいた、冷徹なまでの最適化である。
コメント