【実務・中級編】 カラムとデータ型 – Cloud Spanner

Cloud Spannerの「データ型」を極める:その選択がシステムの寿命を決める

Spannerの設計において、スキーマ定義は単なるデータ格納の器ではない。それは、世界規模の分散トランザクションを支える「物理的な制約」と「パフォーマンスの境界線」を定義する行為だ。

多くのエンジニアが犯すミスは、RDBMSの感覚で安易に型を選び、後になってから「なぜかパフォーマンスが出ない」「なぜかストレージコストが跳ね上がった」と頭を抱えることだ。

今日は、Spannerのデータ型を「単なる入れ物」としてではなく、分散データベースの深淵に触れるツールとして、実務の現場で直面する設計の要諦を叩き込む。

—

1. 数値型の選択:FLOAT64という「毒」

まず、金銭や厳密さが求められる計算において `FLOAT64` を使うのは禁じ手だ。浮動小数点数は誤差を生む。金融取引や残高管理でこれを使うことは、システムに時限爆弾を仕込むのと同じだ。

  • NUMERIC / PG.NUMERIC: 精度を求めるならこれ一択。最大38桁の精度を持ち、固定小数点演算を行う。
  • INT64: IDやカウントにはこれで十分だが、主キーに使う場合は注意が必要だ。

【設計の勘所】
主キーに `INT64` を使い、連番(シークエンシャル)にすると、「ホットスポット」が発生する。Spannerは範囲分割でデータを分散させるため、書き込みが特定のノードに集中し、スループットが頭打ちになる。
対策: IDには `UUID (STRING(36))` を使用するか、ビット反転させた `INT64` を使い、書き込みを分散させるのがプロの作法だ。

2. STRINGとBYTESの「長さ」という罠

`STRING(MAX)` は便利に見える。だが、Spannerにおいて「最大長」を定義しないことは、最適化の機会を放棄しているのと同義だ。

  • STRING(N): 可能な限り具体的な長さを定義すべきだ。インデックスのサイズはキーの長さに比例する。巨大な文字列をインデックスに含めれば、それだけでメモリ消費が激増し、レイテンシが悪化する。
  • BYTES: バイナリデータやシリアライズしたオブジェクト用。`STRING` と同様、サイズ設計がストレージコストに直結する。

3. JSON型:柔軟性とパフォーマンスのトレードオフ

最近追加された `JSON` 型は強力だ。しかし、注意が必要だ。

  • 「何でも入れる」の代償: JSON型の中に複雑な構造を詰め込むと、SQLでのクエリ効率が落ちる。
  • インデックス戦略: JSON内部のパスに対してインデックスを貼ることは可能だが、多用すると更新時の書き込み増幅(Write Amplification)が顕著になる。

【実務の定石】
「頻繁に検索・フィルタリングする項目」はJSONから剥がし、明示的なカラムとして定義せよ。JSONはあくまで「スキーマ変更のコストを払いたくないメタデータ用」と割り切るのが、大規模運用の鉄則だ。

4. ARRAY型:パフォーマンスの諸刃の剣

`ARRAY` は、リレーションを減らすための強力な武器になる。例えば、「ユーザーのタグ」や「過去の履歴」を別テーブルに切らずにARRAYで保持すれば、JOINなしで取得できるため劇的に高速だ。

【注意点】
ARRAYの要素数が増えすぎると、一つの行サイズが極端に大きくなる。Spannerには行サイズ制限はないが、「行が大きすぎるとI/O効率が落ちる」という物理的な現実がある。1行あたりのサイズは数MB以下に抑える設計が健全だ。

5. TIMESTAMP:時空の支配者

Spannerにおける `TIMESTAMP` は `spanner.commit_timestamp()` と組み合わせて使う。これは分散システムにおいて「どのデータが最新か」を決定するための最強の武器だ。

— データの最終更新日時を自動で記録する(テーブル定義)
CREATE TABLE Users (
UserId STRING(36) NOT NULL,
UpdatedAt TIMESTAMP OPTIONS (allow_commit_timestamp=true)
) PRIMARY KEY (UserId);

— 書き込み時に活用する
INSERT INTO Users (UserId, UpdatedAt)
VALUES (‘user_001’, PENDING_COMMIT_TIMESTAMP());

このアプローチは、アプリケーション層で時刻を生成するよりも遥かに信頼性が高い。分散環境での時刻同期問題から解放される唯一の道だ。

—

チーフアーキテクトからの提言:設計レビューのチェックリスト

君がこれから設計を行う際、以下の問いを自分に投げかけてほしい。

1. 「その型は、本当にインデックスが必要か?」

  • インデックスを貼るなら、そのカラムのサイズを最小に絞り込め。

2. 「ホットスポットを回避しているか?」

  • 主キーの先頭カラムが単調増加になっていないか?

3. 「将来の検索要件を予測できているか?」

  • JSONで誤魔化していないか? 検索が必要なデータは、型を明示してカラムを定義しろ。

4. 「データ型の更新を恐れていないか?」

  • Spannerはオンラインでのスキーマ変更が強力だ。最初から「完璧な型」を目指すより、まずは要件を満たす最小の型から始め、必要に応じて `ALTER TABLE` を叩く勇気を持て。

Spannerは、君が書いたコードの「質」をそのままスループットとして返してくれる正直なデータベースだ。データ型へのこだわりは、そのままシステムの「格」となる。

今日の設計を、妥協なきものに仕上げてくれ。健闘を祈る。

コメント

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