【テクニカル・上級編】 テーブル設計の基本原則 – Cloud Spanner

Cloud Spanner:物理レイヤから逆算する「究極のテーブル設計」論

Cloud Spannerは、単なる「水平スケールするRDBMS」ではない。それは、Googleの巨大な分散基盤上で、TrueTime APIという物理的な時間同期メカニズムを抽象化し、強整合性とグローバルな可用性を物理限界ギリギリで両立させた「分散システムという名の有機体」だ。

我々がSpannerでテーブルを定義する際、意識すべきは「SQLの構文」ではない。「Split(スプリット)がいかにして物理的なノード間をマイグレーションし、タブレットがどのようにメモリ上に展開されるか」という、データプレーンの鼓動である。

本稿では、教科書的な説明を排し、Spannerの深淵に潜む設計思想について語る。

—

1. プライマリキーは「単なるID」ではない

Spannerのテーブル設計において、プライマリキー(PK)はデータそのもの以上に重要だ。SpannerはPKの順序に基づいてデータを物理的にソートし、`Table Split`という単位でノードに分散させる。

禁忌:単調増加する値(Sequential Keys)の利用

`UUID v4`のようなランダムな値をPKに選ぶのは定石だが、`TIMESTAMP`や連番をPKの先頭に据えると、特定のタブレットに書き込み負荷が集中する。

  • 深層知見: 書き込み負荷が特定ノードに偏ると、Spannerの自動分割アルゴリズムが追いつく前に、当該ノードのCPU/メモリがホットスポット化する。これを避けるには、PKの先頭に「シャードキー(分散用ハッシュ)」を付与するか、Bit-reversed sequenceを利用して書き込みを物理的に散らす必要がある。

2. データ型:その1bitの重み

Spannerのデータ型選択は、単にアプリケーションの制約を満たすためではない。それは「メモリ効率」と「シリアライゼーション・コスト」の最適化である。

  • STRING vs BYTES:
  • `STRING`は内部でUTF-8エンコーディングされる。もし格納するのがバイナリデータなら、迷わず`BYTES`を選べ。`STRING`の検証コストを排除し、ストレージ効率と比較演算のオーバーヘッドを最小化できる。
  • JSON型:
  • JSONは強力だが、クエリでの抽出コストは構造化データに劣る。頻繁にフィルタ条件として使うカラムはJSONから分離し、カラムとして定義せよ。Spannerのオプティマイザは、列指向のストレージレイヤを活用して、JSON内の個々のパスよりもカラムベースのアクセスを劇的に高速化する。
  • ARRAY型:
  • 非正規化の切り札だが、注意が必要だ。`ARRAY`は単一のタブレット内に格納される。巨大な配列を一つの行に詰め込むと、その行の読み取り時に巨大なメモリ割り当てが発生し、GC(ガベージコレクション)を誘発する原因となる。

3. インタリーブ(Interleaving):物理的局所性の極致

Spannerの真骨頂は、親テーブルと子テーブルを物理的に同じタブレット(同じノードのディスク)に配置する「インタリーブ」にある。

— 親テーブル
CREATE TABLE Users (
UserId INT64 NOT NULL,
— …
) PRIMARY KEY (UserId);

— 子テーブル(インタリーブ定義)
CREATE TABLE UserLogs (
UserId INT64 NOT NULL,
LogId INT64 NOT NULL,
— …
) PRIMARY KEY (UserId, LogId),
INTERLEAVE IN PARENT Users ON DELETE CASCADE;

  • アーキテクトの視点:
  • この設計により、`JOIN`操作が「ノード間通信(Shuffle)」から「ローカルメモリ上のポインタ参照」へと昇華する。分散システムにおける最大の敵であるネットワークレイテンシを、テーブル定義の段階で無効化する技術だ。これを活用しない設計は、Spannerを使っているとは言えない。

4. 限界への挑戦:ストレージとインデックスのトレードオフ

インデックス(Secondary Index)は便利だが、それは「書き込み増幅」の代償を伴う。Spannerにおけるインデックスは、それ自体が独立したテーブルとして管理される。

  • 書き込みコスト: 1つのインデックスを追加するたびに、書き込み時の分散トランザクションの参与ノードが増える可能性がある。
  • 解決策: 「本当にそのインデックスが必要か?」を自問せよ。頻繁なフィルタリングが必要なカラムを、PKの構成要素に組み込むことで、インデックスなしで高速なスキャンを実現できないか検討する。PK設計こそが、Spannerにおける最強のインデックスである。

—

結びに代えて:アーキテクトの矜持

Cloud Spannerを使いこなすということは、分散システムの複雑性を理解した上で、あえて「単純で堅牢なデータ構造」を選択するということだ。

設計の指針は常にシンプルである。
1. 物理的局所性をデザインせよ(インタリーブを活用し、関連するデータは物理的に近くに置く)。
2. ホットスポットを排除せよ(PKの選定で書き込みを全ノードに拡散させる)。
3. 型を最適化せよ(不要な変換コストを排除し、ストレージ効率を突き詰める)。

データベースは、単なる情報の器ではない。システムの血流だ。その流速と循環を支配するのは、SQLではなく、君たちが定義したそのテーブルの構造である。

次回の運用編では、この物理設計を前提とした「バックプレッシャーの制御とトランザクションの最適化」について掘り下げるとしよう。エンジニアの戦いは、まだ始まったばかりだ。

コメント

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