PostgreSQL から Spanner(PostgreSQL 言語)に移行する

このページでは、オープンソースの PostgreSQL データベース(以降 PostgreSQL)を Spanner PostgreSQL 言語データベース(以降 Spanner)に移行する方法について説明します。

Spanner と GoogleSQL 言語への移行については、PostgreSQL から Spanner(GoogleSQL 言語)への移行をご覧ください。

移行の制約

Spanner では、特定のコンセプトの扱いが他のエンタープライズ データベース管理ツールとは異なるため、その機能を最大限に活用するにはアプリケーションのアーキテクチャを調整する必要がある場合があります。ニーズを満たすために、Spanner を Google Cloud の他のサービスで補完する必要がある場合もあります。

ストアド プロシージャとトリガー

Spanner はデータベース レベルでのユーザーコードの実行をサポートしていないため、移行の一環として、データベースのストアド プロシージャとトリガーによって実装されたビジネス ロジックをアプリケーションに移す必要があります。

シーケンス

Spanner では、主キー値を生成するデフォルトの方法として UUID バージョン 4 を使用することをおすすめします。GENERATE_UUID() 関数(GoogleSQLPostgreSQL)は、STRING 型で表される UUID バージョン 4 の値を返します。

整数値を生成する必要がある場合は、Spanner でビット反転した正のシーケンス(GoogleSQLPostgreSQL)がサポートされ、これにより 64 ビットの正の数空間に均等に分散する値が生成されます。ホットスポットの問題を回避するため、これらの数値を使用できます。

詳細については、主キーのデフォルト値戦略をご覧ください。

アクセス制御

Spanner は、テーブルレベルと列レベルできめ細かいアクセス制御をサポートしています。ビューに対するきめ細かいアクセス制御はサポートされていません。詳細については、細かいアクセス制御についてをご覧ください。

移行プロセス

移行には次のタスクが含まれます。

  • PostgreSQL スキーマを Spanner にマッピングする。
  • SQL クエリを変換する。
  • Spanner のインスタンス、データベース、スキーマを作成する。
  • アプリケーションをリファクタリングして Spanner データベースと連携できるようにする。
  • データを移行する。
  • 新しいシステムを検証して本番稼働状態に移行する。

ステップ 1: PostgreSQL スキーマを Spanner にマッピングする

データベースをオープンソース PostgreSQL から Spanner に移行するための最初のステップは、どのようなスキーマ変更が必要かを判断することです。

主キー

Spannerでは、いずれのテーブルでも、複数の行を保存する必要がある場合は、そのテーブルの 1 つ以上の列からなる主キーが必要になります。テーブルの主キーはテーブル内の各行を一意に識別します。Spanner は主キーを使用してテーブルの行を並べ替えます。Spanner は高度に分散されているため、データの増加に合わせて適切にスケーリングできる主キー生成手法を選択することが重要です。詳細については、推奨される主キーの移行戦略をご覧ください。

主キーを指定した後は、後でテーブルを削除して再作成しない限り、主キー列を追加または削除したり、主キーの値を変更したりすることはできません。主キーの指定方法の詳細については、スキーマとデータモデルの主キーをご覧ください。

インデックス

PostgreSQL の B-tree インデックスは、Spanner のセカンダリ インデックスと似ています。Spanner データベースでは、パフォーマンスを向上させる目的でよく検索される列にインデックスを付けたり、テーブルで指定された UNIQUE 制約を代用するためにセカンダリ インデックスを使用します。たとえば、PostgreSQL DDL に次のステートメントがあるとします。

 CREATE TABLE customer (
    id CHAR (5) PRIMARY KEY,
    first_name VARCHAR (50),
    last_name VARCHAR (50),
    email VARCHAR (50) UNIQUE
 );

この場合、Spanner DDL では次のようなステートメントを使用します。

CREATE TABLE customer (
   id VARCHAR(5) PRIMARY KEY,
   first_name VARCHAR(50),
   last_name VARCHAR(50),
   email VARCHAR(50)
   );

CREATE UNIQUE INDEX customer_emails ON customer(email);

任意の PostgreSQL テーブルのインデックスを見つけるには、psql\di メタコマンドを実行します。

必要なインデックスが判明したら、CREATE INDEX ステートメントを追加してそれらを作成します。セカンダリ インデックスのガイダンスに従ってください。

Spanner はインデックスをテーブルとして実装するので、単調増加する列(TIMESTAMP データを含む列など)にインデックスを付けると、ホットスポットが発生することがあります。ホットスポットを回避する方法の詳細については、DBA が Spanner について知っておくべきこと、パート 1: キーとインデックスをご覧ください。

Spanner ではテーブルと同じ方法でセカンダリ インデックスが実装されるため、インデックス キーとして使用される列値にはテーブルの主キーと同じ制約が適用されます。したがって、Spanner のテーブルと同様にインデックスの整合性も保証されます。

セカンダリ インデックスを使用した値検索は、テーブル結合を使用したクエリと実質的に同じです。INCLUDE 句を使用して元のテーブルの列値のコピーをセカンダリ インデックスに保存して Covering index とすることで、インデックスを使用したクエリのパフォーマンスが向上します。

Spanner のクエリ オプティマイザでは、クエリの対象となるすべての列がセカンダリ インデックス自体に保存されている場合(カバードクエリ)に限り、セカンダリ インデックスが自動的に使用されます。元のテーブルの列をクエリするときにインデックスを強制的に使用するには、次の例に示すように、SQL ステートメントで FORCE INDEX ディレクティブを使用する必要があります。

SELECT *
FROM MyTable /*@ FORCE_INDEX=MyTableIndex */
WHERE IndexedColumn=$1;

次に、Albums テーブルにセカンダリ インデックスを作成する DDL ステートメントの例を示します。

CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle);

データの読み込み後に追加のインデックスを作成すると、インデックスへのデータの入力に時間がかかることがあります。追加する頻度を 1 日平均 3 回に制限することをおすすめします。セカンダリ インデックスの作成方法の詳細については、セカンダリ インデックスをご覧ください。インデックス作成の制限事項の詳細については、スキーマの更新をご覧ください。

ビュー

Spanner ビューは読み取り専用です。データの挿入、更新、削除には使用できません。詳細については、ビューをご覧ください。

生成列

Spanner は生成された列をサポートしています。構文の違いと制限については、生成された列を作成、管理するをご覧ください。

テーブル インターリーブ

Spanner には、1 対多の親子関係を持つ 2 つのテーブルを定義できる機能があります。この機能を使用すると、ストレージ内でデータ行の親子がインターリーブされます。これにより、テーブルが効果的に事前結合され、親と子をともに対象とするクエリでより効率的なデータ取得が可能になります。

子テーブルの主キーは、親テーブルの主キー列で始まる必要があります。子行の観点からは、親行の主キーは外部キーとなります。最大 6 レベルの親子関係を定義できます。

子テーブルに対してON DELETEアクションを定義すると、親行が削除された場合の動作を指定できます。子行をすべて削除するか、子行が存在する間は親行の削除をブロックするかのいずれかの動作を選択できます。

次に、Albums テーブルを作成して、前に定義した親の Singers テーブルにインターリーブする例を示します。

CREATE TABLE Albums (
 SingerID      bigint,
 AlbumID       bigint,
 AlbumTitle    varchar,
 PRIMARY KEY (SingerID, AlbumID)
 )
 INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

詳細については、インターリーブされたテーブルを作成するをご覧ください。

データ型

次の表に、Spanner 用の PostgreSQL Interface でサポートされていないオープンソースの PostgreSQL データ型を示します。

データ型 代わりに使用
bigserial,serial8 bigint, int8
bit [ (n) ] -
bit varying [ (n) ], varbit [ (n) ] -
box -
character [ (n) ], char [ (n) ] 文字の変更
cidr テキスト
circle -
inet テキスト
整数、int64 bigint, int8
interval [fields] [ (p) ] bigint
json jsonb
line -
lseg -
macaddr テキスト
money numeric、decimal
パス -
pg_lsn -
point -
polygon -
realfloat4 double precision, float8
smallint, int2 bigint, int8
smallserial, serial2 bigint, int8
serial, serial4 bigint, int8
time [ (p) ] [ without time zone ] HH:MM:SS.sss 表記を使用した。
time [ (p) ] with time zonetimetz HH:MM:SS.sss+ZZZZ 表記を使用した。または、2 つの列を使用します。
timestamp [ (p) ] [ without time zone ] text または timestamptz
tsquery -
tsvector -
txid_snapshot -
uuid text または bytea
xml テキスト

ステップ 2: SQL クエリを変換する

Spanner には、変換の負担を軽減するために利用できるオープンソースの PostgreSQL の多くの関数があります。

SQL クエリを実行する際には、Google Cloud コンソールの [Spanner Studio] ページを使用してクエリのプロファイリングを行うことができます。一般に、大きなテーブルを対象としてテーブル全体のスキャンを実行するクエリには非常にコストがかかるため、使用は控えめにする必要があります。SQL クエリの最適化の詳細については、SQL のベスト プラクティスのドキュメントをご覧ください。

ステップ 3: Spanner インスタンス、データベース、スキーマを作成する

インスタンスを作成し、PostgreSQL 言語でデータベースを作成します。次に、PostgreSQL データ定義言語(DDL)を使用してスキーマを作成します。

pg_dump を使用して、PostgreSQL データベース内のオブジェクトを定義する DDL ステートメントを作成し、前のセクションの説明に従ってステートメントを変更します。DDL ステートメントを更新したら、DDL ステートメントを使用して Spanner インスタンスにデータベースを作成します。

詳しくは以下をご覧ください。

ステップ 4: アプリケーションをリファクタリングする

変更されたスキーマと改訂された SQL クエリを考慮し、プロシージャやトリガーなどのデータベースに常駐するロジックを置き換えるアプリケーション ロジックを追加します。

ステップ 5: データを移行する

データを移行する方法は 2 つあります。

  • Harbourbridge を使用する。

    Harbourbridge は、スキーマとデータの両方の移行をサポートしています。pg_dump ファイルまたは CSV ファイルをインポートできます。また、オープンソースの PostgreSQL データベースに直接接続してインポートすることもできます。

  • COPY FROM STDIN コマンドを使用します。

    詳細については、データをインポートする COPY コマンドをご覧ください。