Oracle® OLTP システムから Cloud Spanner への移行

この記事では、データベースを Oracle® オンライン トランザクション処理(OLTP)システムから Cloud Spanner に移行する方法について説明します。

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

移行の制約

アプリケーションを Cloud Spanner に移行する際には、利用可能なさまざまな機能を考慮する必要があります。Cloud Spanner の機能セットに適合させたり、その他の GCP サービスと統合したりするために、アプリケーション アーキテクチャを再設計する必要がある可能性があります。

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

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

シーケンス

Cloud Spanner ではシーケンス ジェネレータは実装されません。次に説明するように、Cloud Spanner では通常、単調に増加する数を主キーとして使用することはありません。その代わりに、ランダムな UUID を使用して一意の主キーを生成できます。

Cloud Spanner の外部でシーケンスが必要とされる場合は、それらをアプリケーション レイヤに実装する必要があります。

アクセス制御

Cloud Spanner は、Cloud IAM のアクセス許可と役割を使用したデータベース レベルのアクセス制御のみをサポートしています。事前定義された役割を使用すると、データベースに対する読み取り / 書き込みアクセスまたは読み取り専用アクセスを付与できます。

よりきめ細かな権限を必要とする場合は、それらをアプリケーション レイヤに実装する必要があります。通常のシナリオでは、アプリケーションにのみデータベースに対する読み取りおよび書き込みを許可する必要があります。

データベースをレポート用にユーザーに公開する必要があり、きめ細かなセキュリティ権限(テーブルレベルやビューレベルの権限など)を使用する場合は、データベースを BigQuery にエクスポートする必要があります。

データ検証制約

Cloud Spanner は、データベース レイヤで一部のデータ検証制約をサポートしています。

より複雑なデータ制約が必要な場合は、それらをアプリケーション レイヤに実装します。

次の表に、Oracle® データベースで一般的に見られる制約の種類、およびそれらを Cloud Spanner で実装する方法を示します。

制約 Cloud Spanner での実装
null 以外 NOT NULL 列の制約
一意 UNIQUE 制約付きのセカンダリ インデックス
外部キー(通常のテーブル用) アプリケーション レイヤに実装
外部キーの ON DELETE/ON UPDATE アクション インターリーブされたテーブルでのみ使用可能で、それ以外の場合はアプリケーション レイヤに実装
CHECK 制約またはトリガーによる値の確認と検証 アプリケーション レイヤに実装

サポートされているデータ型

Oracle® データベースと Cloud Spanner ではそれぞれ異なるデータ型がサポートされます。次の表に、Oracle のデータ型とそれに対応する Cloud Spanner のデータ型を示します。Cloud Spanner の各データ型の定義の詳細については、データ型をご覧ください。

Oracle のデータを Cloud Spanner データベースに適合させるために、備考列の説明に沿って、データに対して追加の変換を実行する必要がある場合もあります。

たとえば、大きな BLOB をデータベースではなく Cloud Storage バケットにオブジェクトとして保存してから、Cloud Storage オブジェクトへの URI 参照を STRING としてデータベースに保存できます。

Oracle のデータ型 Cloud Spanner の対応するデータ型 備考
文字型(CHARVARCHARNCHARNVARCHAR STRING 注: Cloud Spanner では全体的に Unicode 文字列が使用されます。
Oracle は最大 32,000 バイトまたは文字(型によって異なる)をサポートしているのに対し、Cloud Spanner は最大 2,621,440 文字をサポートしています。
BLOBLONG RAWBFILE オブジェクトへの URI を含む BYTES または STRING 小さなオブジェクト(10 MiB 未満)は BYTES として保存できます。
より大きなオブジェクトを保存する際には、Cloud Storage などの代替 GCP サービスの使用を検討してください。
CLOBNCLOB, LONG STRING(データまたは外部オブジェクトへの URI を含む) 小さなオブジェクト(2,621,440 文字未満)は STRING として保存できます。より大きなオブジェクトを保存する際には、Cloud Storage などの代替 GCP サービスの使用を検討してください。
NUMBERNUMERICDECIMAL STRINGFLOAT64INT64 Oracle の NUMBER データ型は最大 38 桁の精度をサポートしているのに対し、Cloud Spanner の FLOAT64 データ型は最大 16 桁の精度をサポートしています。代替メカニズムについては、任意精度の数値データの保存をご覧ください。
INTINTEGERSMALLINT INT64
BINARY_FLOATBINARY_DOUBLE FLOAT64
DATE DATE Cloud Spanner の DATE 型のデフォルトの STRING 表現は yyyy-mm-dd です。これは Oracle のものとは異なるため、日付の STRING 表現との間で自動変換を行う場合は注意が必要です。日付を書式設定済み文字列に変換するための SQL 関数が提供されています。
DATETIME TIMESTAMP Cloud Spanner では時間はタイムゾーンから切り離して保存されます。タイムゾーンを保存する必要がある場合は、個別の STRING 列を使用する必要があります。タイムスタンプをタイムゾーン付きの書式設定済み文字列に変換するための SQL 関数が提供されています。
XML STRING(データまたは外部オブジェクトへの URI を含む) 小さな XML オブジェクト(2,621,440 文字未満)は STRING として保存できます。より大きなオブジェクトを保存する際には、Cloud Storage などの代替 GCP サービスの使用を検討してください。
URIDBURIXDBURIHTTPURI STRING
ROWID PRIMARY KEY Cloud Spanner ではテーブルの主キーを使用して内部的に行を並べ替えたり、参照したりしているため、Cloud Spanner では実質的に主キーが ROWID データ型と同じ働きをします。
SDO_GEOMETRYSDO_TOPO_GEOMETRY_SDO_GEORASTER   Cloud Spanner は地理空間データ型をサポートしていません。標準のデータ型を使用してこのデータを保存し、検索およびフィルタリング ロジックはアプリケーション レイヤに実装する必要があります。
ORDAudioORDDicomORDDocORDImageORDVideoORDImageSignature Cloud Spanner はメディアデータ型をサポートしていません。メディアデータを保存する際には、Cloud Storage の使用を検討してください。

移行プロセス

移行プロセスの全体的なタイムラインは次のようになります。

  • スキーマとデータモデルを変換します。
  • SQL クエリを変換します。
  • Oracle に加えて Cloud Spanner を使用するようにアプリケーションを移行します。
  • Oracle からデータを一括エクスポートし、Cloud Dataflow を使用して、そのデータを Cloud Spanner にインポートします。
  • 移行時には、両方のデータベース間で整合性を維持します。
  • アプリケーションを Oracle から移行します。

データベースとスキーマを変換する

既存のスキーマを Cloud Spanner のスキーマに変換してデータを保存します。アプリケーションの変更を簡単にするために、既存の Oracle スキーマとできるだけ一致させる必要があります。ただし、機能の違いにより、いくつかの変更が必要になります。

スキーマ設計のおすすめの方法に従うと、Cloud Spanner データベースのスループットを向上させ、ホットスポットを減らすことができます。

主キー

いずれのテーブルでも、複数の行を保存する必要がある場合は、そのテーブルの 1 つ以上の列からなる主キーが必要になります。テーブルの主キーはテーブル内の各行を一意に識別します。また、テーブルの行は主キーで並べ替えられるため、テーブル自体が主インデックスとして機能します。

単調に増減する列(シーケンスやタイムスタンプなど)を主キーの最初の部分として指定しないでください。キースペースの最後に挿入が集中してホットスポットが生じる可能性があります。ホットスポットとは単一ノードへのオペレーションの集中であり、この現象が発生すると、書き込みが複数の Cloud Spanner ノード間で負荷分散されないため、書き込みスループットが 1 つのノードの容量までに制限されます。

次の手法を使用して、一意の主キー値を生成し、ホットスポットのリスクを軽減できます。

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

次に、音楽トラックのデータベース用のテーブルを作成する DDL ステートメントの例を示します。

CREATE TABLE Singers (
  SingerId   INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  SingerInfo BYTES(MAX),
  BirthDate  DATE,
) PRIMARY KEY(SingerId);

テーブルをインターリーブする

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

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

子テーブルに対して削除時アクションを定義して、親行の削除が実行されたときの動作を指定できます。つまり、子行がすべて削除されるようにするか、子行が存在する間は親行の削除がブロックされるようにすることができます。

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

CREATE TABLE Albums (
  SingerId     INT64 NOT NULL,
  AlbumId      INT64 NOT NULL,
  AlbumTitle   STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId)
INTERLEAVE IN PARENT (Singers)
ON DELETE CASCADE;

セカンダリ インデックスを作成する

セカンダリ インデックスを作成して、テーブル内のデータを主キー以外でインデックス登録することもできます。

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

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

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

SELECT *
FROM MyTable@{FORCE_INDEX=MyTableIndex}
WHERE IndexedColumn=@value

インデックスを使用してテーブルの列内の値を一意にするには、その列に UNIQUE インデックスを定義します。重複する値の追加はインデックスによって防止されます。

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

CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle);

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

SQL クエリを変換する

Cloud Spanner は、拡張機能を含む ANSI 2011 SQL に対応し、データの変換や集計に役立つ多数の関数と演算子を備えています。Oracle 固有の構文、関数、型を使用する SQL クエリについては、Cloud Spanner との互換性を保つために変換する必要があります。

Cloud Spanner では構造化データを列定義として使用することはできませんが、ARRAY 型と STRUCT 型を使用すれば、SQL クエリで構造化データを扱うことができます。

たとえば、1 つのクエリで STRUCTsARRAY を使用して(事前結合されたデータを利用して)、アーティストのすべてのアルバムを返せます。詳細については、ドキュメントのサブクエリに関する注意セクションをご覧ください。

SQL クエリを実行する際には、GCP Console の Cloud Spanner クエリ インターフェースを使用してクエリのプロファイリングを行うことができます。一般に、大きなテーブルを対象としてテーブル全体のスキャンを実行するクエリには非常にコストがかかるため、使用は控えめにする必要があります。

SQL クエリの最適化の詳細については、SQL のベスト プラクティス ドキュメントをご覧ください。

Cloud Spanner を使用するようにアプリケーションを移行する

Cloud Spanner は、さまざまな言語用のクライアント ライブラリを備えています。また、データの読み取りや書き込みには、Cloud Spanner 固有の API 呼び出しを使用することも、SQL クエリデータ変更言語(DML)ステートメントを使用することもできます。キーによって行を直接読み取る場合など一部のクエリでは、API 呼び出しを使用したほうが、処理が速くなることがあります(SQL ステートメントの変換が不要であるため)。

Java Database Connectivity(JDBC)ドライバを使用して Cloud Spanner に接続し、ネイティブに統合されていない既存のツールやインフラストラクチャを利用することもできます。

移行プロセスの一環として、Cloud Spanner で利用できない機能をアプリケーションに実装する必要があります。たとえば、データ値を検証して関連テーブルを更新するトリガーは、既存の行の読み取り、制約の検証、更新された行の両方のテーブルへの書き込みという一連の処理を実行する読み取り / 書き込みトランザクションを使用して、アプリケーションに実装する必要があります。

Cloud Spanner は、読み取り / 書き込みトランザクションおよび読み取り専用トランザクションを備えており、これらのトランザクションを通じてデータの外部整合性が保証されます。さらに、読み取りトランザクションには、次の方法で指定した整合性のあるデータ バージョンを読み取るようにタイムスタンプ バウンドを適用できます。

  • 過去の正確な時刻(最大 1 時間前まで)。
  • 将来の時刻(その時間になるまで読み取りがブロックされる)。
  • 許容範囲内のバウンド ステイルネス。最新のデータが別のレプリカで利用可能かどうかをチェックすることなく、過去の特定の時点までの整合性のあるビューが返されます。この方法を使用すると、パフォーマンス上の利点が得られる代わりに、データが古くなる可能性があります。

Oracle から Cloud Spanner にデータを転送する

Oracle から Cloud Spanner にデータを転送するには、Oracle データベースをポータブル ファイル形式(CSV など)にエクスポートしてから、Cloud Dataflow を使用してそのデータを Cloud Spanner にインポートする必要があります。

Cloud Dataflow での抽出、変換、読み込みの処理

Oracle から一括でエクスポートする

Oracle には、データベース全体をポータブル ファイル形式にエクスポートまたはアンロードするための組み込みユーティリティは用意されていません。

Oracle FAQ に、エクスポートを実行する際に使用できるいくつかのオプションが記載されています。

一部を次に示します。

  • SQL*plus または SQLcl を使用して、クエリをテキスト ファイルにスプールします。
  • テーブルをテキスト ファイルに並列にアンロードするために、UTL_FILE を使用した PL/SQL 関数を記述します。
  • Oracle APEX または Oracle SQL Developer 内の機能を使用して、テーブルを CSV または XML ファイルにアンロードします。

これらのいずれについても、一度に 1 つのテーブルしかエクスポートできないという欠点があります。つまり、エクスポートする際には、データベースの整合性を維持するために、アプリケーションを一時停止するか、データベースを静止する必要があります。

Oracle FAQ ページに記載されているサードパーティ ツールを使用するという選択肢もあります。これらのツールの中には、データベース全体の整合性のあるビューをアンロードできるものもあります。

アンロードが終了したら、データファイルを Cloud Storage バケットにアップロードして、インポートできるようにする必要があります。

Cloud Spanner に一括でインポートする

Oracle と Cloud Spanner ではデータベース スキーマが異なる可能性があるため、インポート プロセスでデータ変換が必要になる場合があります。

このようなデータ変換処理と Cloud Spanner へのデータのインポートは、Cloud Dataflow を使用すると最も簡単に実行できます。

Cloud Dataflow は、GCP から配信される抽出、変換、読み込み(ETL)サービスです。このサービスは、Apache Beam SDK で記述されたデータ パイプラインを実行するプラットフォームです。これにより、複数のマシン上の大量のデータを並列に読み取って処理できます。

Apache Beam SDK では、簡単な Java プログラムを記述するだけで、データの読み取り、変換、書き込みを実装できます。Cloud Storage と Cloud Spanner 用のビームコネクタが標準装備されているため、実際にコーディングが必要なのはデータ変換部分だけです。

この記事に付属のサンプル コード リポジトリで、CSV ファイルから読み取って Cloud Spanner に書き込む単純なパイプラインの例をご覧ください。

親子でインターリーブされたテーブルを Cloud Spanner で使用する場合は、インポート プロセスで親行が子行より先に作成されるように注意する必要があります。したがって、Cloud Spanner のインポート パイプライン コードでは、最初にルートレベルのテーブルのすべてのデータをインポートしてから、レベル 1 のすべての子テーブル、レベル 2 のすべての子テーブル(これ以降も同様)という順序でインポートする必要があります。

Cloud Spanner のインポート パイプラインを直接使用してデータを一括でインポートすることもできますが、この場合、適切なスキーマ設計を持つ Avro ファイルにデータが格納されている必要があります。

両方のデータベース間で整合性を維持する

多くのアプリケーションには可用性要件が定められており、データのエクスポートとインポートに必要な時間だけアプリケーションをオフラインにすることは困難です。つまり、データを Cloud Spanner に転送している間は、引き続き既存のデータベースに変更が反映されることになります。そのため、アプリケーション実行中は、Cloud Spanner データベースへの更新内容を複製する必要があります。

変更データ キャプチャ、アプリケーションでの同時更新の実装など、さまざまな方法で 2 つのデータベースを同期できます。

変更データ キャプチャ

Oracle GoldenGate は、データベースを対象とした変更データ キャプチャ ストリームの提供に対応しています。このストリームにサブスクライブして同じ変更(データ変換後の変更)を Cloud Spanner データベースに適用するアプリケーションを記述できます。

アプリケーションから両方のデータベースを同時に更新する

別の方法は、両方のデータベースへの書き込みを実行するようにアプリケーションを変更することです。一方のデータベース(最初は Oracle)が信頼できる情報源と見なされ、データベースへの書き込みが発生するたびに、行全体が読み取られ、変換されてから Cloud Spanner データベースに書き込まれます。

このようにして、アプリケーションによって常に Cloud Spanner の行が最新のデータで上書きされます。

すべてのデータが正しく転送されたことを確認したら、信頼できる情報源を Cloud Spanner データベースに切り替えることができます。

このメカニズムでは、Cloud Spanner への切り替え時に問題が見つかったとしても、ロールバック パスが確保されています。

データの整合性を検証する

データが Cloud Spanner データベースにストリーミングされるときに、Cloud Spanner データと Oracle データを定期的に比較して、データの整合性を検証できます。

整合性を検証する際には、両方のデータソースに対してクエリを実行し、その結果を比較します。

Cloud Dataflow では、Join 変換を使用して大規模なデータセットに対して詳細な比較を行うことができます。この変換に 2 つのキー付きデータセットを渡すと、対応する値がキー別に照合されます。その後、対応する値を比較して、等しいかどうかを確認できます。

整合性のレベルがビジネス要件を満たすまで、この検証を定期的に実行できます。

アプリケーションの信頼できる情報源を Cloud Spanner に切り替える

データ移行が確実に終了したら、Cloud Spanner を信頼できる情報源として使用するようにアプリケーションを切り替えることができます。以降は、変更を Oracle データベース側にも継続的に反映することで Oracle データベースを最新の状態に保ち、問題が発生した場合のロールバック パスを確保してください。

最終的には、Oracle データベースの更新コードを無効にして削除し、Oracle データベースをシャットダウンできます。

Cloud Spanner データベースをエクスポートしてインポートする

必要に応じて、Cloud Dataflow テンプレートを使用して、Cloud Spanner から Cloud Storage バケットにテーブルをエクスポートできます。その結果、フォルダには、エクスポートされたテーブルを含む一連の Avro ファイルと JSON マニフェスト ファイルが保存されます。これらのファイルは、次のようなさまざまな目的に役立ちます。

  • データ保持ポリシーの遵守または障害復旧のためにデータベースをバックアップできます。
  • Avro ファイルを BigQuery などの他の GCP サービスにインポートできます。

エクスポートおよびインポート プロセスの詳細については、データベースのエクスポートデータベースのインポートをご覧ください。

次のステップ

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...