【入門編】 Generated Columns内部実装 – Cloud Spanner

こんにちは!Cloud Spannerの世界へようこそ。
今日は、データベースの設計において魔法のように便利な機能、「Generated Columns(計算列)」の内部で一体何が起きているのかを、一緒に深く覗いていきましょう。

「計算列って、クエリを書くたびに裏で計算し直しているの?」
「それとも、どこかに保存されていてスペースを食っているの?」

そんな疑問を持ったことはありませんか?
ここをクリアすれば、Cloud Spannerのパフォーマンスの仕組みが一気に見えてきますよ。初心者の方にもスッと腑に落ちるように、身近な例えを交えながら優しく解説していきますね。

—

1. Generated Columns(計算列)ってなに?(日常の例え)

まずは基本のおさらいです。Cloud Spanner(だけでなく一般的なデータベース)における計算列とは、「他の列の値を使って、自動的に計算・生成される列」のことです。

イメージしやすいように、「カフェのレシート」を想像してください。

  • 通常の列: 「カフェラテの値段(500円)」「数量(2杯)」
  • 計算列: 「小計(値段 × 数量)」

普通のデータベースだと、レシートを発行するたびに「500 × 2 = 1000」と計算し直したり、アプリ側で計算してわざわざデータベースに書き込んだりする必要があります。
しかし、計算列を使えば、「値段」と「数量」を入れるだけで、データベース側が自動的に「小計」を計算して保管してくれます。人間で言えば、電卓を叩く仕事をデータベースが裏でこっそりやってくれるようなものです。

—

2. 気になる内部実装:ストレージにはどう保存されているの?

さて、ここからが本題であり、Cloud Spannerの凄腕エンジニアたちが作り込んだ「知見」の部分です。

計算列には、主に2つの保存パターンがあります。
1. 仮想列(Virtual):データは保存せず、読み出す時にその都度計算する。
2. 保存列(Stored):計算結果をあらかじめディスクに保存しておく。

実は、Cloud Spannerの計算列は「ストレージに物理的に保存される(Stored方式)」のが基本です。

これには、分散データベースであるCloud Spannerならではの深い理由があります。

なぜ「保存(Stored)」するのか?

Cloud Spannerは、世界中にデータを分散させ、爆速でクエリを返すモンスターマシンです。もし「仮想列」にしてしまうと、数億行あるデータを検索するたびに、裏でいちいち計算処理(CPUの仕事)が発生してしまいます。これではせっかくの分散処理のスピードが台無しになりますよね。

そのため、Cloud Spannerは「データを書き込む瞬間(インサートやアップデートの時)」に、一度だけ計算を済ませ、その結果を通常の列と一緒にハードディスク(ストレージ)に書き込んでしまいます。

| 値段 (price) | 数量 (quantity) | 小計 (subtotal ※計算列) |
| :— | :— | :— |
| 500 | 2 | 1000 (←この結果がディスクに保存される!) |

つまり、クエリ実行時の再計算コストは「ゼロ」なんです。読み出すときは、あたかも最初からそこに値が入っていたかのように、一瞬でディスクから引っ張り出してきます。

—

3. クエリ実行時の裏側の動き

「じゃあ、クエリを投げたときはどう動いているの?」という疑問がわきますよね。

データがすでにディスクに保存されているため、クエリを実行したときのCloud Spannerの動きは非常にシンプルです。

1. 書き込み時(Write):
ユーザーが `price` と `quantity` を登録する。Cloud Spannerのエンジンが瞬時に「お、`subtotal` は `price quantity` だな」と計算し、ディスクに「1000」と書き込む。
2. 読み込み時(Read):
ユーザーが `SELECT subtotal FROM …` と実行する。Cloud Spannerは一切の計算を行わず、ディスクに保存されている「1000」をそのままネットワークに乗せて返す。

「計算列」という名前ですが、読み込みの瞬間に働いているわけではなく、「書き込みの瞬間に未来の計算を終わらせておく予約席」のようなものなんです。

—

4. 実戦で使える!Cloud Spannerでの定義方法

百聞は一見にしかず。実際にコードを見てみましょう。
ここでは、名と姓から「フルネーム」を自動生成する計算列を作ってみます。

— テーブルの作成
CREATE TABLE Users (
UserId INT64 NOT NULL,
FirstName STRING(50),
LastName STRING(50),

— ここが計算列の定義!
— CONCAT関数を使って、名と姓をスペース区切りで合体させます
FullName STRING(101) AS (CONCAT(FirstName, ‘ ‘, LastName)) STORED,

) PRIMARY KEY(UserId);

ここがポイント:
最後の `STORED` というキーワードに注目してください。「この計算結果はちゃんとディスクに保存してね」というCloud Spannerへの指示です。これがあるおかげで、読み込みが爆速になります。

—

5. さらに一歩進んだ知見:インデックスとの組み合わせ

Cloud Spannerの計算列の真骨頂は、「計算列に対してインデックス(索引)が貼れること」です。

例えば、先ほどの `FullName` でユーザーをすばやく検索したいとします。通常のデータベースだと「計算結果の列にインデックスを貼るのは難しい」ことが多いのですが、Cloud Spannerなら余裕です。

— 計算列(FullName)を使ったセカンダリインデックスの作成
CREATE INDEX UsersByName ON Users(FullName);

ディスクにあらかじめ「計算された結果」が保存されているからこそ、その値を使ったインデックス作成や検索がスムーズに行えるというわけです。この仕組みを理解していると、検索性能を落とさずに、リッチで複雑なデータをテーブル設計に組み込めるようになります。

—

まとめ

いかがでしたでしょうか? 今回のポイントをギュッと凝縮して振り返ってみましょう。

  • 計算列の正体: 値の評価や計算は「データを書き込む時」に行われる。
  • ストレージの仕組み: 計算結果はディスクに物理的に保存される(`STORED`)。
  • クエリ実行時: 再計算は行われず、保存された値をそのまま高速に読み出す。
  • 応用: 保存されているからこそ、インデックスを貼って爆速検索ができる。

ここをクリアすれば、Cloud Spannerのストレージとクエリの連携プレイが頭の中で完全にイメージできるようになります。データベースの裏側の動きが分かると、コードを書くのがもっと楽しくなりますよね。

今日の学びを武器に、ぜひ実際のプロジェクトでも計算列を使いこなしてみてください。
それでは、次のステップでまたお会いしましょう!

コメント

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