Google Cloud Japan
⚒️

フツーのデータベースとしてSpannerを使うには

に公開
2026/08/19

この記事の目的

Spannerはスケーラビリティに優れたデータベースであると説明されることの多い製品です。スケーラビリティの面が強調された結果、「Spannerは何か特殊なデータベースではないか」「名前は聞いたことあるけど、普通のアプリケーションでは使えないんでしょ」というイメージを持たれていると感じています。スケーラビリティに特長があるのは事実ですが、データベースとしてみるとテーブル定義とデータ型があり、トランザクションが実行可能で、SQLでクエリーや更新が行える、いわば「普通のリレーショナルデータベース」としての側面もあります。

実際にSpannerを普通のリレーショナルデータベース(以下、RDB)として使うと、MySQLやPostgreSQLとどこがどのように違うのか、どこを意識すればアプリケーションの移植が可能になるかを解説するのがこの記事の目的となります。後半では普通のRDBと比較してSpannerのスケーラビリティ以外のメリットについて解説します。

Spanner はどれぐらい普通のRDBか

SpannerはGoogleが開発した分散データベースです。2012年に論文として発表され、当初はGoogle社内のサービスで使われていましたが、その後2017年にはクラウドサービスとしても一般に利用可能となりました。当初は専用のAPIでのアクセスのみが提供されていましたが、2017年の論文でSQLによるアクセス方法も実装したことが発表されました。

Spanner以前にもGoogle社内にはBigtableというキーバリューストア(KVS)の一種であるワイドカラム型のデータベースが存在しました。KVSはスケーラビリティやレイテンシーに優れていますが、アプリケーションを開発するという観点ではそのままでは使いにくい場面もあります。複雑なアプリケーションを実装するにはRDBと併用するか、トランザクションの仕組みを独自に実装する必要が出てきます。Spannerでは開発者にとってより使いやすいデータベースを目指してリレーショナルモデルを採用しました。そのため、RDBで慣れ親しんだテーブル定義があり、カラムにはデータ型が存在し、トランザクションによりアトミックな操作が可能です。

クエリーはSELECTで行うことができ、更新は INSERT, DELETE, UPDATE 文が使えます。経緯のところでもご紹介した通り、Spannerの開発当初はAPIによる更新のみが提供されている時期がありました。現在でもAPI(ミューテーション)による更新も利用可能です。バルクロードしたいときなどSQLを書くほどではない場面では、今でもミューテーションの方が便利なときもあります。

Spannerがサポートしている現代的なRDBに求められる機能を列挙してみました。

一覧をみて、一般的なアプリケーションから使う機能は一通り揃っているなと実感いただけるのではないかと思います。さらにローカル環境での開発・テスト向けに公式のSpanner エミュレータ(Dockerコンテナ)も提供されているため、従来のRDBと同様にローカルで手軽に動作確認やCI/CDを構築することが可能です。

接続ライブラリ

接続されないことには話が始まらないので、まずは接続ライブラリから始めます。
Spannerはクライアントアプリケーションとの接続にgRPCを使います。これは既存のRDBとは異なるため、クライアントライブラリは専用のものが開発されています。対応プラットフォームは以下の通りです。

  • C++
  • C#
  • Go
  • Java
  • Node.js
  • PHP
  • Python
  • Ruby

クライアントライブラリはいわばSpannerへのネイティブの接続方法です。
ライブラリの使い方はさほど特殊ではありませんが、Spanner独自の機能や概念を扱うために一般的なRDBのドライバーと少し違う部分もあります(たとえば、SQL以外での更新方法もサポートしている、トランザクションのリトライを考慮しているなど)。
新規のアプリケーションでSpannerのフル機能を活用したい場合はこちらの使用もおすすめですが、一般的なRDBのドライバーに慣れている場合や既存アプリケーションの移植では後述のドライバーを使う方が良い場合もあります。

クライアントライブラリとは別にドライバーというものも提供されています。
クライアントライブラリがSpannerに接続するための専用のライブラリであるのに対して、ドライバーは各言語向けのデータベースを扱うための汎用的な仕組みに沿うようにクライアントライブラリをラップしたものです。具体的にはたとえばJavaでのJDBCやGoのdatabase/sqlがそれにあたります。この仕組みに乗って操作していれば、データベースがMySQLやPostgreSQLでも多くの操作を共通した記述で行うことができます。

ORマッパーもドライバーの一環として提供されています。たとえばJavaのHibernateやRubyのActive Record、PythonのSQLAlchemyなどです。これらを使えば既存のアプリケーションの移植に際して、SQLの書き換えも不要です。

ドライバーは既存アプリケーションを移植するときには便利ですが、Spannerの独自機能などには対応していない場合もあります。各ドライバーとSpannerの機能の対応状況については対応表に記載されています。

まとめると、まったく新規のアプリケーションの場合はクライアントライブラリを使うと良いですが、既存のアプリケーションを移植したいときや開発者にノウハウがあるフレームワークやドライバーからの移行の場合はSpannerのドライバーが便利です。

PostgreSQL互換ドライバー

Spannerはアプリケーションとの間の通信にgRPCベースの独自プロトコルを使っていますが、これをPostgreSQLのワイヤープロトコルに変換するPGAdapterも提供されています。これを使えば、アプリケーションもPostgreSQLへの接続ドライバーをそのまま利用できますので、移植の手間がひとつ省略できます。

PGAdapterはライブラリや独立したソフトウェアのいずれの方法でも利用できます。スタンドアロンでも実行できますし、アプリケーションがコンテナで実行されている場合はPGAdapterをサイドカーとして実行すると良いでしょう。

認証

RDBへの接続にはIDとパスワードの組み合わせを利用されることが多いと思います。Spannerの場合はIAMで認証と認可を行います。

Spannerに限定される話ではありませんが、IAM認証では固定の鍵ファイル(サービスアカウントキー)をコードや環境に配置する方法は漏洩リスクやローテーション問題があるため避けるのが好ましいです。Google Cloud上であればCompute EngineやGKEにサービスアカウントを直接紐付ける形式、実行環境がAWSやAzure等の場合はWorkload Identity連携を使うことで、鍵を使わないキーレス認証(Application Default Credentials)を実現できます。

クラウドでの認証方式に慣れていないとIDとパスワードに比べて煩雑に感じられるかもしれませんが、IAMでの認証はクラウドサービスを使う上では一般的な仕組みですし、IAMとデータベースで二重管理にならずローテーションや漏洩のリスクを避ける手段が確立されているというメリットは大きいと思います。

プライマリキー

ここがRDBとSpannerの一番の違いかもしれません。Spannerには一般的な AUTO INCREMENT はありません。代替としてシーケンスとBIT_REVERSE関数があります。

じゃあ、AUTO INCREMENTを使っているところは機械的にこれに書き換えればいいかと言うと、それはちょっと待ってください。AUTO INCREMENTをプライマリキーとして使う場面の多くで必要なのは以下のような条件ではないでしょうか。

  • データベース側で自動採番される
  • 一意性がある
  • 追記順(昇順)

このとき単調増加する、つまり追記順が保証されている性質が必要ないのであれば、UUIDなど衝突の恐れがほぼない一意な文字列を使うという方法もあります。UUIDの自動生成をデフォルトとする(DEFAULT (GENERATE_UUID()))ことにより、データベースで自動的に生成され重複がないという目的は達成することが可能です。

一方、アプリケーション側で追記順(昇順)の値を扱いたい場合にも、BIT_REVERSE 関数が有効な解決策となります。BIT_REVERSE 関数は数値をビット反転させる関数です。書き込み時にビット反転した値を主キーとして格納することで、データベース上では値をランダムに分散させてホットスポットの発生を防ぎます。そして BIT_REVERSE は可逆な操作(再度 BIT_REVERSE を実行すると元の数値に戻る)であるため、データを取得したあとにアプリケーション側で再度 BIT_REVERSE を行うことで、元の昇順の値を復元して扱うことができます。つまり、「DBのストレージ上では分散させつつ、アプリ上では追記順として扱う」という使い方が可能です。

プライマリキーとして単調増加する数値そのままを使うべきでない理由は、負荷の集中する箇所(ホットスポット)が発生し、それがインスタンス全体の性能のボトルネックになるためです。他の回避策としては、単調増加してほしい範囲が限定できるか検討することです。たとえば、マルチテナントで各テナントの範囲内でのみ昇順・降順の並び替えが欲しいのであれば、tenant_id を第1キーとする複合主キーに設計したり、インターリーブテーブル(親テーブルのデータと子テーブルのデータを物理的に近くに配置する構造)を活用する方法が考えられます。また、更新頻度が高くないマスタテーブルなどでは、昇順のキーを使っていても極端に性能のボトルネックとはならないケースもあります。

SQL

Spannerは2種類のSQL構文をサポートしています。ANSI準拠のGoogleSQLとPostgreSQL互換です。SQLにはANSI標準があるものの、RDBの実装ごとに拡張が多い言語です。そのため、標準への準拠によって相互運用性が保証されるわけではありませんが、基本的な構文については概ね互換性があります。

MySQLを使っている小さいアプリケーションを数本移植した感触としては、SQLの構文レベルでの互換性があるため多くの場合そのままで動作しましたが、関数名や引数の取り方など表記違いの箇所は書き換えが必要でした。

INSERT 〜 ON DUPLICATE KEY UPDATE

MySQLではINSERT時にすでに同じプライマリキーのレコードが存在した場合には更新を、なかったときには追記をするという INSERT 〜 ON DUPLICATE KEY UPDATE 構文があります。PostgreSQLではINSERTの ON CONFLICT句がそれにあたります。この構文は便利なのでアプリケーションで使われることも多いと思います。

この機能はSpanner(GoogleSQL構文)のINSERT OR UPDATEという構文で実現が可能です(PostgreSQL互換構文の場合は ON CONFLICT DO UPDATE も利用できます)。この構文がサポートされる前はトランザクション中でSELECTによる存在確認と、アプリケーションロジックでの分岐によってINSERTとUPDATEを出し分ける必要がありました。この部分の書き換えはロジックの変更を伴うため移植のハードルでしたが、現在はこの構文を使うことにより書き換え箇所を大幅に省略できます。

対話的操作(REPL)

DBを使うアプリを開発しているとMySQLにおけるmysqlコマンド、PostgreSQLにおけるpsqlのようにCLIでSQLを実行し、サッと結果を確認したい時があると思います。Spannerはクラウドサービスとして提供されているため強力なウェブインターフェイスが提供されていますが、CLIで操作するためのコマンド spanner-cliも開発されています。

SELECT文のクエリーを実行する、DMLで更新する、トランザクションを発行する、ヒストリとライン編集機能など基本的な操作が揃っています。その他には実行計画を表形式で表示する、バッチモードで結果をテキストに書き出すなども可能です。Spanner特有の機能としては優先度の指定、トランザクション・リクエストタグをつけて実行なども可能です。(なお、PGAdapter経由やPostgreSQL互換構文を使用している場合は、おなじみの psql コマンドで直接接続することもできます)。

個人的にはロックの挙動を確認するときに、複数のターミナルから横に並べつつ実行してトランザクションを開始してDMLを実行するなどの操作をspanner-cliで行ったりしています。

ちなみに、gcloudコマンドのspannerサブコマンドからSQLを実行することも可能です。

スケーラビリティ以外でのSpannerのメリット

スケーラビリティについては他の記事などでも散々触れられているので、それ以外の話題を中心にSpannerのメリットを解説します。

可用性が高い

Spannerはリージョナル構成で99.99%、マルチリージョンとデュアルリージョン構成で99.999%の可用性のSLAが提供されています。後述の通りメンテナンスウィンドウもないため、この可用性には「メンテナンスウィンドウを除く」といった注釈もありません。

メンテナンスの手間がない

Spannerには内部にコンピュートノードという概念がありますが、ノードへのハードウェアメンテナンスがある場合にもダウンタイムはありません。コンピュートとストレージが分離されており、コンピュートは物理的実体の上で動作していますがそれぞれのコンポーネントは冗長構成となっており、各コンポーネントをダウンタイムなく交換できるためコンピュートのメンテナンスが必要な場合もダウンタイムなしで自動的に実行されます。

これはソフトウェアの更新に関しても同様です。ソフトウェアの更新は順次適用され、更新中にダウンタイムなども生じません。そのため、ソフトウェアアップデートのためのメンテナンスウィンドウの概念も存在しませんし、パッチ適用のためのサービス中断の調整なども必要ありません。

2022年にはSpannerでストレージのレイアウトを変更したという記事を公開しました。ストレージのレイアウト変更はRDBではメジャーバージョンアップで行われるような大きな変更ですが、こういった内部的な大規模アップデートもユーザーへのダウンタイムなしで計画・実施されました。

オンラインでのスキーマ変更(DDL)

運用面で特に大きなメリットとなるのが完全オンラインでのスキーマ変更(DDL)です。一般的なRDBでは大規模テーブルに対する ALTER TABLE(カラム追加やインデックス生成)でテーブルロックが発生し、クエリ処理や書き込みの遅延・タイムアウトのリスクが生じますが、Spannerではダウンタイムやサービスへの影響なしにバックグラウンドで安全に実行されます。

高速で一貫性のある読み取り(Read-Only Transaction)

データの読み取り処理において、普通のRDBではロック競合や読み取り一貫性の制御(分離レベルの考慮)が必要になります。SpannerではTrueTime技術を活用したRead-Only Transaction(読み取り専用トランザクション)が提供されており、ロックを一切取得せずに過去の特定のタイムスタンプや最新の一貫したデータを高速に読み取ることが可能です。画面表示やレポート出力などの読み取り処理にRead-Only Transactionを明示的に使うことで、書き込み処理をブロックせず高いスループットを維持できます。

グラフデータベースとしても使える

2024年8月にSpannerはグラフデータベースへの対応を発表しました。Spannerのグラフデータベース対応はリレーショナルデータベースを拡張する形で提供されます。通常通りテーブルに書き込んだデータに対して、グラフとしてアクセスするときの定義を追加することで、SQLに加えてグラフ用のクエリー言語であるGQL(Graph Query Language/GraphQLとは異なります)でもアクセスできるようになるというものです。

リレーショナルデータベースで複数のテーブルをJOINして結果を得るSQLをよく使われると思います。このような処理はグラフ操作でのノード間の接続をたどる操作に相当します。GQLはグラフをたどる処理がシンプルに記述できます。グラフデータベースでなければ絶対に解けない問題は多くありませんが、SQLで記述すると非常に複雑になる処理もGQLで記述するとシンプルに書ける場合があります。GQLとSQLは混ぜて使うこともできるため、グラフ処理で書きやすい部分はGQLでそれ以外の部分はSQLといった混在も可能です。

データ自体はテーブルにあるため、グラフ操作のために既存のテーブルからデータを移動して二重に持ったり、データを同期する仕組みを作る必要がありません。

全文検索としての機能

全文検索の機能自体は多くのRDBで実装されています。Spannerの全文検索機能は、GoogleのWeb検索で培われた自然言語処理の技術を活かして多言語対応をしているのが特長です。

また、全文検索は更新頻度が高いと全文検索用のインデックスの更新がボトルネックとなる場合がありますが、Spannerでは書き込みのスケーラビリティを向上させる仕組みがあるためノード数を増やすことで書き込み性能もスケールアウトすることが可能です。

Google Cloudの他サービスとの親和性が高い

SpannerはBigQueryを始め、Google Cloudのサービスと連携できます。
SpannerのデータをBigQueryで分析したいときには、DataBoostという仕組みを使うことでSpannerのインスタンスに負荷をかけることなくデータが連携できます。逆にBigQueryで分析した結果を書き戻したい場合には、リバースETLを使えばBigQuery上ではクエリーを書くだけで連携できます。

その他、汎用的なCDCの仕組みであるDatastreamでデータを書き込む、Vertex AIを使ってMLのモデルで推論を行うなども可能です。

まとめ

この記事では、Spannerを従来のRDBとして活用する方法について解説しました。主なポイントは以下のとおりです。

  • Spannerはスケーラビリティだけでなく、従来のリレーショナルデータベースと同様の機能(SQL、トランザクション、データ型など)を備えています。
  • Spannerへの接続には、クライアントライブラリとドライバー(JDBC、ORMなど)の2種類の方法があり、既存アプリケーションの移植にはドライバーの使用が有効です。ローカル開発にはエミュレータも利用できます。
  • プライマリキーの設計においては、AUTO INCREMENT の代替として DEFAULT (GENERATE_UUID()) や BIT_REVERSE 関数(分散用)などを適切に選択する必要があります。
  • Spannerはスケーラビリティに加えて、高可用性、完全オンラインのメンテナンス/スキーマ変更、Read-Only Transaction、グラフデータベース機能、全文検索機能など、一般的なRDBと比較しても数多くの実用的なメリットを提供します。

現在は最小100 Processing Units(0.1ノード相当)や無料トライアルから利用を開始できます。これらの特徴を理解することで、Spannerを「普通のRDB」として効果的に活用し、アプリケーション開発や移植に役立てることができるでしょう。

GitHubで編集を提案
Google Cloud Japan
Google Cloud Japan

Discussion