スキーマの更新

Cloud Spanner を使用すると、ダウンタイムなしでスキーマの更新を行うことができます。いくつかの方法で既存のデータベースのスキーマを更新できます。

サポートされているスキーマの更新

Cloud Spanner は、既存のデータベースに対する次のスキーマ更新をサポートしています。

  • 新しいテーブルを作成する。新しいテーブルの列は NOT NULL にできます。
  • テーブルを削除する(そのテーブル内で他のテーブルがインターリーブされておらず、セカンダリ インデックスがない場合)。
  • 任意のテーブルに非キー列を追加する。新しい非キー列は NOT NULL にできません。
  • 非キー列に NOT NULL を追加する。
  • 非キー列から NOT NULL を削除する。
  • 任意のテーブルから非キー列を削除する(セカンダリ インデックスで使用されていない場合)。
  • STRING 列を BYTES 列に、または BYTES 列を STRING 列に変更する。
  • STRING 型または BYTES 型の長さ制限を増やす、または減らす(MAX への変更を含む)(1 つまたは複数の子テーブルによって継承されている主キー列ではない場合のみ)。
  • 値列と主キー列の commit タイムスタンプを有効または無効にする。
  • セカンダリ インデックスを追加または削除する。

スキーマ更新のパフォーマンス

Cloud Spanner のスキーマの更新には、ダウンタイムは必要ありません。DDL 文のバッチを Cloud Spanner データベースに対して発行した場合、Cloud Spanner が更新を長時間実行オペレーションとして適用する間も、中断なくデータベースでの書き込みと読み取りを続けることができます。

DDL 文の実行に要する時間は、更新で既存のデータの検証が必要か、データのバックフィルが必要かによって異なります。たとえば、NOT NULL アノテーションを既存の列に追加する場合、Cloud Spanner は列にすべての値を読み取って、列に NULL 値が含まれていないことを確認する必要があります。検証が必要なデータが多い場合、この手順には長い時間がかかる可能性があります。もう 1 つの例は、データベースにインデックスを追加する場合です。Cloud Spanner が既存のデータを使用してインデックスをバックフィルします。このプロセスは、インデックスの定義と対応するベーステーブルのサイズに応じて時間がかかることがあります。ただし、テーブルに新しい列を追加する場合は、検証が必要な既存のデータがないため、Cloud Spanner はより迅速に更新できます。

まとめると、Cloud Spanner による既存のデータの検証が不要なスキーマ更新は、数分で行うことができます。検証が必要なスキーマ更新にかかる時間は、検証が必要な既存のデータの量に応じて長くなりますが、データの検証は本番環境トラフィックよりも低い優先度でバックグラウンドで行われます。データの検証が必要なスキーマ更新の詳細については後述します。

データの検証が必要なスキーマ更新

スキーマ更新に伴い、既存のデータが新しい制約を満たすことの検証を要求されることがあります。スキーマ更新によってデータの検証が要求されると、Cloud Spanner は影響を受けるスキーマ エンティティに対する競合するスキーマ更新を禁止し、バックグラウンドでデータを検証します。検証に成功すると、スキーマ更新は成功します。検証が成功しなかった場合、スキーマ更新は成功しません。検証オペレーションは、長時間実行オペレーションとして実行されます。これらのオペレーションのステータスを確認して、オペレーションが成功したか失敗したかを判断できます。

たとえば、スキーマで Songwriters テーブルを定義したとします。

CREATE TABLE Songwriters (
  Id         INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  Nickname   STRING(MAX),
  OpaqueData BYTES(MAX),
) PRIMARY KEY (Id);

次のようなスキーマ更新は許可されますが、検証が必要であり、既存データの量によっては完了するのに時間がかかる場合があります。

  • NOT NULL アノテーションを非キー列に追加する。

    例: ALTER TABLE Songwriters ALTER COLUMN Nickname STRING(MAX) NOT NULL

  • 列の長さを短くする。

    例: ALTER TABLE Songwriters ALTER COLUMN FirstName STRING(10)

  • BYTESSTRING に変更する。

    例: ALTER TABLE Songwriters ALTER COLUMN OpaqueData STRING(MAX)

  • 既存の TIMESTAMP 列で commit タイムスタンプを有効にする。

    例: ALTER TABLE Albums ALTER COLUMN LastUpdateTime SET OPTIONS (allow_commit_timestamp = true)

基になっているデータが新しい制約を満たさない場合、これらのスキーマ更新は失敗します。たとえば、上の ALTER TABLE Songwriters ALTER COLUMN Nickname STRING(MAX) NOT NULL 文は、Nickname 列のいずれかの値が NULL の場合、既存のデータが新しい定義の NOT NULL 制約を満たさないため、失敗します。

データの検証には、数分で済むこともあれば、何時間もかかる場合もあります。データ検証に要する時間は以下のことに依存します。

  • データセットのサイズ
  • インスタンスのノードの数
  • インスタンスの負荷

スキーマ更新によっては、スキーマ更新が完了する前にデータベースに対するリクエストの動作が変わる場合があります。たとえば、NOT NULL を列に追加する場合、Cloud Spanner はほとんど瞬時に、列に NULL を使用する新しいリクエストの書き込みの拒否を開始します。新しいスキーマ更新のデータ検証が最終的に失敗する場合、古いスキーマでは受け付けられていた場合でも、書き込みがブロックされる期間が発生する可能性があります。

projects.instances.databases.operations.cancel メソッドまたは gcloud spanner operations を使用すると、実行時間の長いデータ検証オペレーションをキャンセルできます。

バッチ内の文の実行順序

gcloud ツール、REST API、RPC API を使用する場合は、1 つ以上の CREATEALTERDROP ステートメントのバッチを発行できます。

Cloud Spanner では、同じバッチの文を順番に適用し、最初のエラーで停止します。ある文の適用でエラーが発生した場合、その文はロールバックされます。バッチ内の以前に適用された文の結果はロールバックされません。

Cloud Spanner によってさまざまなバッチの文が組み合わされて並べ替えられることがあるため、データベースに適用される 1 つのアトミック変更の中に、複数のバッチの文が混在する可能性があります。それぞれのアトミック変更内で、さまざまなバッチの文が任意の順序で出現します。たとえば、あるバッチの文に ALTER TABLE MyTable ALTER COLUMN MyColumn STRING(50) が含まれ、別のバッチの文には ALTER TABLE MyTable ALTER COLUMN MyColumn STRING(20) が含まれている場合、Cloud Spanner によって列がこのいずれかの状態になりますが、どちらの状態になるかは指定できません。

スキーマの更新中に作成されたスキーマのバージョン

Cloud Spanner ではスキーマのバージョニングが使用されるため、大規模なデータベースへのスキーマの更新中にダウンタイムが発生しません。Cloud Spanner では、スキーマの更新処理中の読み取りをサポートするために、古いスキーマ バージョンを維持します。その後、Cloud Spanner によって、スキーマの更新を処理するために、1 つ以上の新しいバージョンのスキーマが作成されます。各バージョンには、上記のように、1 回のアトミック変更での文のコレクションの結果が含まれます。スキーマのバージョンは、必ずしも DDL 文のバッチまたは個々の DDL 文とで、1 対 1 で対応しているとは限りません。インターリーブされていないインデックス作成やデータ検証が必要な文など、一部の個々の DDL 文では、複数のスキーマ バージョンが発生します。また、いくつかの DDL 文は、1 つのバージョンでまとめてバッチ処理できます。複数のスキーマ バージョンが発生することで、サーバーとストレージのリソースが大幅に消費される可能性があります。複数のスキーマ バージョンが存在する状態は、最大で 1 週間続きます。

次の表に、スキーマ更新オペレーションの期間を示します。

スキーマのオペレーション 推定時間
CREATE TABLE 数分
CREATE INDEX

数分から数時間(インデックスがインターリーブされていない場合)。インデックスの作成には、小さいテーブルや空のテーブルでも時間がかかることがあります。

数分(インデックスがインターリーブされ、ベーステーブルの CREATE TABLE と同時に実行される場合)。

DROP TABLE 数分
DROP INDEX 数分
ALTER TABLE ... ADD COLUMN 数分
ALTER TABLE ... ALTER COLUMN

数時間(バックグラウンド検証が必要な場合)。

数分(バックグラウンド検証が不要な場合)。

ALTER TABLE ... DROP COLUMN 数分

スキーマの更新に関するベスト プラクティス

以下のセクションでは、スキーマを更新するためのベスト プラクティスについて説明します。

スキーマ更新を発行する前の手順

スキーマの更新を発行する前に:

  • 変更しているデータベース内の既存のすべてのデータが、スキーマ更新が課している制約を満たしていることを確認します。一部のタイプのスキーマ更新の成功は、現在のスキーマだけでなく、データベース内のデータに依存するため、テスト データベースのスキーマ更新が成功しても、本番環境データベースのスキーマ更新が成功するとは限りません。いくつかの一般的な例を以下に示します。
    • 既存の列に NOT NULL アノテーションを追加する場合、列に既存の NULL 値が含まれないことを確認します。
    • STRING 型または BYTES 型の列に許可されている長さを短くする場合、その列の既存のすべての値が必要な長さの制約を満たしていることを確認します。
  • スキーマ更新を行っている列、テーブル、インデックスに書き込む場合は、書き込む値が新しい制約を満たすようにします。
  • 列、テーブル、インデックスを削除する場合には、それが作成中または読み取り中でないことを確認してください。

7 日間のスキーマ更新の数の制限

単一のデータベースのスキーマに対して多くのスキーマ更新を 7 日間以内に行うことは避けてください。Cloud Spanner で新しいバージョンが作成される前に古いバージョンのスキーマを削除できるように、より長い期間でスキーマの更新を行います。

  • 一部のリレーショナル データベース管理システムには、本番環境のデプロイのたびに、データベースに対する長い一連のアップグレードとダウングレードのスキーマ更新を行うソフトウェア パッケージがあります。これらのタイプのプロセスは、Cloud Spanner では推奨されません。
  • Cloud Spanner は、主キーを使用してマルチテナンシー ソリューション用にデータを分割するように最適化されています。お客様ごとに個別のテーブルを使用するマルチテナンシー ソリューションでは、スキーマ更新オペレーションのバックログが大きくなり、完了に時間がかかる可能性があります。

文ごとに複数のバージョンのスキーマが内部的に作成されるため、DDL 文で検証やインデックスのバックフィルを必要とする場合は、7 日間以内に 30 を超える文を発行することは避けてください。

大規模なスキーマ更新のオプション

多数のインデックスを持つデータベースを作成する場合、特にインデックスがインターリーブされていない場合は、次のいずれかの方法を使用します。

  • データベース作成リクエストでデータベースとそのスキーマの両方を作成する。Cloud Spanner では、データの検証、複数のスキーマ バージョンの格納、並行トランザクションとのスキーマ変更の調整を行う必要がないため、データベース作成時のテーブルとインデックスの作成オペレーションは迅速になります。
  • データベースを作成してから、新しいインデックスを平均で 1 日あたり 3 つ追加する。

多数の DDL 文を含むスキーマ更新がある場合は、projects.instances.databases.updateDdl(REST API)または UpdateDatabaseDdl(RPC API)リクエストを使用して一度に少しずつ実行することは避けてください。より大きなグループでバッチ処理してください。1 回のリクエストで数千の DDL 文をバッチ処理できますが、それらの文のうち、検証やバックフィルを要求できる文は 10 個までとなります。検証とバックフィルの制限は、Cloud Spanner の文を組み合わせる機能と Cloud Spanner が作成するスキーマ バージョンの数によるものです。バッチ処理を行う場合でも、追加するインデックスの数は 1 日あたり約 3 つに制限してください。

API リクエストの完了の待機

projects.instances.databases.updateDdl(REST API)リクエストまたは UpdateDatabaseDdl(RPC API)リクエストを行う場合は、それぞれ projects.instances.databases.operations.get(REST API)または GetOperation(RPC API)を使用して、新しいリクエストを開始する前に各リクエストの完了を待機します。各リクエストが完了するまで待機すると、アプリケーションがスキーマ更新の進行状況を追跡できます。また、保留中のスキーマ更新のバックログが管理可能なサイズに保持されます。

一括読み込み

テーブルを作成した後にテーブルにデータを一括して読み込む場合は、通常、データの読み込み後にインデックスを作成する方が効率的です。複数のインデックスを追加する場合は、大規模なスキーマ更新のオプションで説明しているように、初期スキーマのすべてのテーブルとインデックスを使用してデータベースを作成する方が効率的な場合があります。

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

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

Cloud Spanner のドキュメント