【実務・中級編】 インターリーブテーブル – Cloud Spanner

Cloud Spannerの「インターリーブ」という名の最強の武器:物理配置を支配し、レイテンシをねじ伏せる設計術

Spannerをただの「SQLが書ける分散DB」だと思っているなら、それは大きな勘違いだ。分散環境における最大の敵は、ネットワーク越しに発生するノード間通信(Shuffle)にある。

リレーショナルデータベースの設計において、結合(JOIN)はコストが高い。これは単一インスタンスのDBでも真理だが、分散DBにおいては「物理的に離れた場所にデータがある」ことが致命的なパフォーマンス劣化を招く。

ここで登場するのが「インターリーブ(Interleave)」だ。これは単なるデータ構造の話ではなく、「データ配置をエンジニアが物理的にコントロールし、分散のオーバーヘッドをゼロにする」ための高度な最適化手法である。

—

1. インターリーブの本質:なぜ「物理的な近接性」が重要なのか

通常、Spannerはデータを主キーの範囲に基づいて「スプリット(Split)」という単位に分割し、ノード全体にバラ撒く。しかし、インターリーブを使うと、子テーブルの行を親テーブルの行と物理的に同じスプリット内に混在させて格納できる。

これにより、親の主キーに関連する子テーブルの検索は、ネットワークをまたぐRPCを一切発生させず、単一ノード内でのローカル・メモリ・アクセス(あるいはローカル・ディスク・アクセス)として完結する。

階層構造の定義例

— 親テーブル:Users
CREATE TABLE Users (
UserId INT64 NOT NULL,
UserName STRING(MAX),
) PRIMARY KEY (UserId);

— 子テーブル:UserOrders
— INTERLEAVE IN PARENT を指定することで、Usersテーブルと同じスプリットに配置される
CREATE TABLE UserOrders (
UserId INT64 NOT NULL,
OrderId INT64 NOT NULL,
Amount INT64,
) PRIMARY KEY (UserId, OrderId),
INTERLEAVE IN PARENT Users ON DELETE CASCADE;

この定義により、`UserId=100`のユーザーデータと、そのユーザーの全注文データは、必ず同じスプリットに配置されることが保証される。

—

2. 結合クエリの「革命」

インターリーブされたテーブルに対する結合クエリは、Spannerのクエリオプティマイザにとって「神の啓示」のようなものだ。

— 親と子をJOINしても、物理的に同じ場所にあるためShuffleが発生しない
SELECT
u.UserName,
o.OrderId,
o.Amount
FROM Users AS u
JOIN UserOrders AS o ON u.UserId = o.UserId
WHERE u.UserId = 100;

通常のJOINであれば、`Users`と`UserOrders`のデータを集めるために内部的にShuffle(ノード間通信)が走る可能性がある。しかし、インターリーブされている場合、オプティマイザは「この結合は同一ノードで完結できる」と判断し、ローカル・インデックス・スキャンとして実行する。これは単一テーブルへのクエリとほぼ同等の速さだ。

—

3. 実務で「絶対に踏んではいけない」地雷

インターリーブは強力だが、銀の弾丸ではない。設計を誤ると、システム全体のパフォーマンスが崩壊する。

注意点1:ホットスポットの集中

インターリーブは、親テーブルの主キーに基づいたスプリットにデータを集中させる。もし親テーブルのキーが特定の範囲に極端に偏るような設計(例:シーケンシャルなIDのみで構成されたテーブル)だと、特定のスプリットに負荷が集中し、Spannerの真骨頂であるスケーラビリティが失われる。

注意点2:スプリットサイズの上限

インターリーブされた子テーブルのデータがあまりに巨大化すると、そのスプリットは限界に達し、再分割(Split)が走る。しかし、親と子が密結合しているため、この再分割は非常にコストが高い。「無限に成長するテーブル」と「その子」を無批判にインターリーブするのは危険だ。

注意点3:親の削除コスト

`ON DELETE CASCADE`を付ける場合、親の行を1つ削除すると、それに紐づくすべての子行が同時に削除される。もし1ユーザーに対して100万件の子レコードがある場合、その削除処理は非常に重いトランザクションとなり、ロック競合を引き起こす。

—

4. チーフアーキテクトからの設計指針

私がレビューで「インターリーブすべきか?」と問われたら、以下の基準で判断する。

1. アクセス頻度: 親の行を読み取る際、かなりの確率で子も読み取るか?(YESであれば即採用)
2. 主キーの構成: 親の主キーが、子テーブルの主キーの接頭辞に含まれているか?(含まれていないなら物理配置の最適化は困難)
3. データ量の予測: 1つの親レコードに対して、子レコードが「数万〜数十万」程度の規模に収まるか?(数百万を超えるなら、インターリーブを外すか、別のシャード戦略を検討する)

結論として:
インターリーブは、「関連するデータを物理的に引き寄せて、分散のコストを殺す」ための究極のチューニングだ。しかし、それは「データ構造をビジネス要件と物理配置の両面から深く理解した者にのみ許された特権」である。

君たちが設計するテーブルが、単なるデータの入れ物ではなく、Spannerという巨大な分散エンジンを最も効率的に駆動させるための「精密機械」であることを忘れないでほしい。

さて、君のスキーマ設計を見せてもらおうか。そこに最適化の余地は残されているかな?

コメント

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