SQLAlchemy 向け Google Cloud Spanner 言語
Google Cloud Japan Team
※この投稿は米国時間 2021 年 12 月 11 日に、Google Cloud blog に投稿されたものの抄訳です。
このたび、SQLAlchemy 向け Google Cloud Spanner 言語の一般提供を開始したことをお知らせします。これにより、SQLAlchemy アプリケーションは Cloud Spanner のスケール、強整合性、最大 99.999% の可用性を享受できます。SQLAlchemy は Python SQL ツールキットおよびオブジェクト リレーショナル マッパーとして、SQL の機能と柔軟性をアプリケーション デベロッパーに提供します。オブジェクト リレーショナル マッパー(ORM)により、オブジェクト モデルとデータベース スキーマを明確に分離して開発できるほか、基盤となる SQL とオブジェクト リレーションの詳細がユーザーにもわかりやすくなっています。
ここでは、この言語の使用方法を示すとともに、サポートされている Spanner 特有の機能をご紹介します。
言語のセットアップ
お使いのアプリケーションで SQLAlchemy 向け Cloud Spanner 言語をセットアップするには、PyPI から提供されているパッケージをインストールします。
ソースからも言語をインストールできます。
Cloud Spanner のセットアップ
Cloud Spanner の使用を開始する前に:
設定ガイドに従って、クラウド プロジェクトの構成、認証、認可を行います。
次に Cloud Spanner のインスタンスとデータベースを Cloud Console を使用したクイックスタートの手順に沿って作成します。
クイックスタート アプリケーション
Engine を作成する
まず、Cloud Spanner データベースとの接続に使用する Engine を作成します。入力として Database URL を使用できます。形式は次のようになります。テーブルを作成する
その後、Engine にバインドされる MetaData オブジェクトを作成し、Table オブジェクトとそのスキーマのコレクションを保持できるようにします。「Singers」、「Albums」、「Tracks」を表す 3 つのテーブルを宣言し、MetaData.create_all() を呼び出してテーブルを作成します。
テーブル間の関係を定義するために、2 つの異なるアプローチを使用しています。
Album は、「Albums」テーブルに「SingerId」を含めることで、外部キー制約を用いて Singer を参照します。これにより各 Album が既存の Singer レコードを参照すること、Singer を削除するとその Singer のすべての Album も削除されることが保証されます。
Track は、「spanner_interleave_in」キーワード引数で構成することで親の「Albums」テーブルにインターリーブされることによって、Album を参照します。これにより、すべての Track レコードが親である Album と物理的に一緒に保存されることになり、一緒にアクセスすることがより効率的になります。「spanner_interleave_on_delete_cascade」を設定すると、Album が削除された場合にインターリーブされた Track も削除されます。また、Table.add_is_dependent_on() も呼び出して、Tracks テーブルの前に Albums テーブルが作成されるようにします。
データの挿入
データは、Table.insert() メソッドを Connection.execute() から呼び出すことで、作成したテーブルに挿入できます。uuid モジュールを使用して主キーフィールドを生成することで、単調増加するキーの作成を回避し、ホットスポットを引き起こさないようにします。
データのクエリ
その後、select() ステートメントを Connection.execute() から実行することで、挿入したデータをクエリできます。
既存のデータベースの移行
SQLAlchemy 向け Cloud Spanner 言語は、Alembic を介した移行をサポートしています。
移行スクリプトによって DDL ステートメントが多数生成される場合には、各ステートメントを個別に実行すると移行が遅くなります。そのため、Alembic のバッチ コンテキスト機能を使用して、DDL ステートメントを複数のステートメントのグループにまとめることを強くおすすめします。
ベスト プラクティス
最適なパフォーマンスを実現するには、明示的な接続を使用し、複数のクエリで接続を再利用します。
暗黙的な接続を使用することも可能ですが、おすすめしません。理由は、Connection.execute() で呼び出すたびに、言語からデータベースへの新しい接続の確立が必要になるからです。そのため、以下のような呼び出しは避けてください。
機能
トランザクション サポート
デフォルトでは、接続はすべてのトランザクションを ReadWrite モードで実行します。ただし、次の例のように、接続の作成時に「read_only」の実行オプションが指定されている場合は、ReadOnly モードでトランザクションを実行できます。
分離レベル
この言語は「SERIALIZABLE」と「AUTOCOMMIT」の分離レベルをサポートしています。「SERIALIZABLE」はデフォルトの分離レベルで、トランザクションは明示的に commit される必要があります。「AUTOCOMMIT」分離レベルが選択されると、各ステートメントが自動的に commit されます。
分離レベルは次のように設定する必要があります。
Cloud Spanner の機能
上述のインターリーブされたテーブルや生成列以外にも、次の Cloud Spanner の機能が SQLAlchemy のプロバイダによってサポートされています。
クエリのヒント
Cloud Spanner はさまざまなステートメントのヒントやテーブルのヒントをサポートしており、言語内では Query.with_hint() を使用して構成できます。この例では、テーブルのヒントを設定する方法を示しています。
ステイル読み取り
Cloud Spanner には 2 種類の読み取りがあります。デフォルトでは、すべての読み取り専用のトランザクションが強力な読み取りを実行します。この例のように、明示的なタイムスタンプの範囲を使用することで、データのクエリ時にステイル読み取りを行うようにすることができます。ステイル読み取りを行うには、接続は「read_only」でなければなりません。
相違点と制限事項
UNIQUE 制約
Cloud Spanner は、UNIQUE 制約の直接作成をサポートしていません。列の値の一意性を確保するためには、この例に示すように UNIQUE インデックスを使用する必要があります。
トランザクション内での DDL
Cloud Spanner では、トランザクション内で DDL ステートメントの実行はできません。そのため、トランザクションのロールバック時に DDL ステートメントがロールバックされることはありません。
Spanner のミューテーション
この言語、および基盤となっている DB API ドライバは、ミューテーションをサポートしていません。そのため、更新の実行に使用できるのは DML ステートメントのみです。
その他の制限事項
「WITH RECURSIVE」ステートメントと名前の付いたスキーマは、Spanner でサポートされていないため、この言語でもサポートの対象外となっています。
「CREATE TEMPORARY TABLE」は、Spanner でサポートされていないため、この言語でもサポートの対象外となっています。
Spanner の数値型に任意のスケールおよび精度を使用することはできないため、数値型のスケールと精度は固定されています。
貢献のお願い
SQLAlchemy 向け Google Cloud Spanner 言語は GitHub のオープンソース プロジェクトです。フィードバックや pull リクエストの形での貢献を歓迎しています。
このインテグレーションに携わってくださった Skylar Pottinger 氏、Ilya Gurov 氏、Hemang Chothani 氏、Alex Vaksman 氏、Knut Olav Løite 氏に感謝いたします。