REST で Spanner を使ってみる


目標

このチュートリアルでは、REST を利用して Cloud Spanner API を使用するステップを詳しく説明します。

  • Spanner インスタンスとデータベースを作成します。
  • データベースのデータに対し、書き込み、読み取り、SQL クエリの実行を行います。
  • データベース スキーマを更新します。
  • セカンダリ インデックスをデータベースに追加します。
  • インデックスを使用して、データの読み込みと SQL クエリの実行を行います。
  • 読み取り専用トランザクションを使用してデータを取得します。

REST API ではなく Spanner クライアント ライブラリを使用する場合は、チュートリアルをご覧ください。

費用

このチュートリアルで使用する Spanner は、Google Cloud の有料コンポーネントです。Spanner を使用する際の料金については、料金をご覧ください。

始める前に

  1. Google Cloud アカウントにログインします。Google Cloud を初めて使用する場合は、アカウントを作成して、実際のシナリオでの Google プロダクトのパフォーマンスを評価してください。新規のお客様には、ワークロードの実行、テスト、デプロイができる無料クレジット $300 分を差し上げます。
  2. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  3. Google Cloud プロジェクトで課金が有効になっていることを確認します

  4. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  5. Google Cloud プロジェクトで課金が有効になっていることを確認します

REST 呼び出しの作成方法

Spanner REST 呼び出しは、以下の方法で作成できます。

このページで使用されている規則

  • ここでの例では [PROJECT_ID] を Google Cloud プロジェクト ID として使用しています。[PROJECT_ID] は実際の Google Cloud プロジェクト ID に置き換えてください。(プロジェクト ID には [] を使用しないでください。)

  • ここでの例ではインスタンス ID test-instance を作成して使用します。test-instance を使用しない場合は自分のインスタンス ID に置き換えてください。

  • ここでの例ではデータベース ID example-db を作成して使用します。example-db を使用しない場合は自分のデータベース ID に置き換えてください。

  • ここでの例では [SESSION] をセッション名の一部として使用しています。[SESSION] は、セッションの作成時に生成される値に置き換えてください。(セッション名には [] を使用しないでください。)

  • ここでの例ではトランザクション ID [TRANSACTION_ID] を使用します。[TRANSACTION_ID] はトランザクションの作成時に生成される値に置き換えてください。(トランザクション ID には [] を使用しないでください。)

  • 試してみましょう機能を使用すると、各 HTTP リクエスト フィールドをインタラクティブに追加できます。このトピックの例の大部分では、リクエストに個別のフィールドをインタラクティブに追加する方法を説明する代わりに、リクエスト全体を使用しています。

インスタンス

Spanner を最初に使用する場合は、インスタンスを作成する必要があります。インスタンスとは、Spanner データベースによって使用されるリソースの割り当てのことです。インスタンスの作成時には、データの保存場所とインスタンスの持つコンピューティング容量を選択します。

インスタンス設定の一覧取得

インスタンスの作成時には「インスタンス構成」を指定し、そのインスタンスのデータベースの地理的位置とレプリケーションを定義します。1 つのリージョンにデータを格納するリージョン構成、または複数のリージョンにデータを分散するマルチ リージョン構成を選択できます。詳しくは、インスタンスをご覧ください。

projects.instanceConfigs.list を使用して、自分の Google Cloud プロジェクトで使用できる構成を特定します。

  1. projects.instanceConfigs.list をクリックします。
  2. [parent] に以下のように入力します。

    projects/[PROJECT_ID]
    
  3. [実行] をクリックします。使用可能なインスタンス構成がレスポンスに表示されます。レスポンスの例を以下にあげます(実際のプロジェクトではインスタンス構成が異なる場合があります)。

    {
      "instanceConfigs": [
        {
          "name": "projects/[PROJECT_ID]/instanceConfigs/regional-asia-south1",
          "displayName": "asia-south1"
        },
        {
          "name": "projects/[PROJECT_ID]/instanceConfigs/regional-asia-east1",
          "displayName": "asia-east1"
        },
        {
          "name": "projects/[PROJECT_ID]/instanceConfigs/regional-asia-northeast1",
          "displayName": "asia-northeast1"
        },
        {
          "name": "projects/[PROJECT_ID]/instanceConfigs/regional-europe-west1",
          "displayName": "europe-west1"
        },
        {
          "name": "projects/[PROJECT_ID]/instanceConfigs/regional-us-east4",
          "displayName": "us-east4"
        },
        {
          "name": "projects/[PROJECT_ID]/instanceConfigs/regional-us-central1",
          "displayName": "us-central1"
        }
      ]
    }
    

インスタンスの作成時にインスタンス構成のいずれかに name 値を使用します。

インスタンスの作成

  1. projects.instances.create をクリックします。
  2. [parent] に以下のように入力します。

    projects/[PROJECT_ID]
    
  3. [Add request body parameters] をクリックして instance を選択します。

  4. インスタンスのヒントのふきだしをクリックして、使用可能なフィールドを確認します。以下のフィールドで値を追加します。

    1. nodeCount: 「1」を入力します。
    2. config: インスタンス構成の一覧表示で返されたいずれかのリージョン インスタンス構成の name 値を入力します。
    3. displayName: 「Test Instance」を入力します。
  5. インスタンスの閉じかっこの後にあるヒントのふきだしをクリックして instanceId を選択します。

  6. instanceId に「test-instance」を入力します。
    試してみましょうのインスタンス作成ページは次のようになります。

    インスタンス作成のスクリーンショット

  7. [実行] をクリックします。レスポンスで長時間実行オペレーションが返されます。これをクエリするとステータスを確認できます。

インスタンスを一覧表示するには、projects.instances.list を使用します。

データベースの作成

example-db という名前のデータベースを作成します。

  1. projects.instances.databases.create をクリックします。
  2. [parent] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance
    
  3. [Add request body parameters] をクリックして createStatement を選択します。

  4. createStatement に以下のように入力します。

    CREATE DATABASE `example-db`
    

    (データベース名 example-db にはハイフンがあるため、バッククォート(`)で囲む必要があります)

  5. [実行] をクリックします。レスポンスで長時間実行オペレーションが返されます。これをクエリするとステータスを確認できます。

データベースを一覧表示するには、projects.instances.databases.list を使用します。

スキーマの作成

Spanner の データ定義言語(DDL)はテーブルの作成、変更、削除、またはインデックスの作成や削除に使用されます。

  1. projects.instances.databases.updateDdl をクリックします。
  2. [database] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db
    
  3. [Request body] で以下のように入力します。

    {
      "statements": [
        "CREATE TABLE Singers ( SingerId INT64 NOT NULL, FirstName STRING(1024), LastName STRING(1024), SingerInfo BYTES(MAX) ) PRIMARY KEY (SingerId)",
        "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"
      ]
    }
    

    statements 配列にはスキーマを定義する DDL ステートメントが含まれます。

  4. [実行] をクリックします。レスポンスで長時間実行オペレーションが返されます。これをクエリするとステータスを確認できます。

スキーマでは、基本的な音楽アプリケーション用の 2 つのテーブル SingersAlbums が定義されています。これらのテーブルはこのページ全体で使用されています。まだスキーマ例を見ていない場合は確認してください。

スキーマを取得するには、projects.instances.databases.getDdl を使用します。

セッションを作成する

データの追加、更新、削除、クエリを行うには、その前にセッションを作成する必要があります。セッションは Spanner データベース サービスとの通信チャンネルを表します。(Spanner クライアント ライブラリを使用している場合は直接セッションを使用せず、このクライアント ライブラリが代わりにセッションを管理します。)

  1. projects.instances.databases.sessions.create をクリックします。
  2. [database] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db
    
  3. [Execute] をクリックします。

  4. 応答には作成したセッションが以下の形式で表示されます。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    このセッションはデータベースで読み取りまたは書き込みを行う場合に使用します。

セッションは長時間の使用を前提としています。Spanner データベース サービスでは、アイドル状態が 1 時間を超えたセッションを削除できます。削除済みのセッションの使用を試みると NOT_FOUND が発生します。このエラーが発生した場合は、新しいセッションを作成して使用します。セッションがまだ維持されているかどうかを確認するには、projects.instances.databases.sessions.get を使用します。関連情報については、アイドル セッションを維持するをご覧ください。

次のステップでは、データベースにデータを書き込みます。

データを書き込む

データを書き込むには、Mutation タイプを使用します。Mutation はミューテーション オペレーションのコンテナです。Mutation は、Spanner データベース内のさまざまな行やテーブルに対してアトミックに適用される一連の操作(挿入、更新、削除など)を表します。

  1. projects.instances.databases.sessions.commit をクリックします。
  2. [session] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (この値はセッションの作成時に取得します)

  3. [Request body] で以下のように入力します。

    {
      "singleUseTransaction": {
        "readWrite": {}
      },
      "mutations": [
        {
          "insertOrUpdate": {
            "table": "Singers",
            "columns": [
              "SingerId",
              "FirstName",
              "LastName"
            ],
            "values": [
              [
                "1",
                "Marc",
                "Richards"
              ],
              [
                "2",
                "Catalina",
                "Smith"
              ],
              [
                "3",
                "Alice",
                "Trentor"
              ],
              [
                "4",
                "Lea",
                "Martin"
              ],
              [
                "5",
                "David",
                "Lomond"
              ]
            ]
          }
        },
        {
          "insertOrUpdate": {
            "table": "Albums",
            "columns": [
              "SingerId",
              "AlbumId",
              "AlbumTitle"
            ],
            "values": [
              [
                "1",
                "1",
                "Total Junk"
              ],
              [
                "1",
                "2",
                "Go, Go, Go"
              ],
              [
                "2",
                "1",
                "Green"
              ],
              [
                "2",
                "2",
                "Forever Hold Your Peace"
              ],
              [
                "2",
                "3",
                "Terrified"
              ]
            ]
          }
        }
      ]
    }
    
  4. [実行] をクリックします。レスポンスに commit タイムスタンプが表示されます。

この例では insertOrUpdate を使用しています。Mutations のその他のオペレーションには、insertupdatereplacedelete があります。

データ型をエンコードする方法については、TypeCode をご覧ください。

SQL を使用したデータのクエリ

  1. projects.instances.databases.sessions.executeSql をクリックします。
  2. [session] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (この値はセッションの作成時に取得します)

  3. [Request body] で以下のように入力します。

    {
      "sql": "SELECT SingerId, AlbumId, AlbumTitle FROM Albums"
    }
    
  4. [実行] をクリックします。レスポンスにクエリの結果が表示されます。

読み取り API を使用したデータの読み込み

  1. projects.instances.databases.sessions.read をクリックします。
  2. [session] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (この値はセッションの作成時に取得します)

  3. [Request body] で以下のように入力します。

    {
      "table": "Albums",
      "columns": [
        "SingerId",
        "AlbumId",
        "AlbumTitle"
      ],
      "keySet": {
        "all": true
      }
    }
    
  4. [実行] をクリックします。レスポンスに読み取りの結果が表示されます。

データベース スキーマの更新

MarketingBudget という列を新たに Albums テーブルに追加する必要があるとします。そのためには、データベース スキーマの更新が必要です。Spanner は、トラフィックを処理する状態にあるデータベースのスキーマの更新をサポートしています。スキーマのアップデートは、データベースをオフラインにする必要はなく、表全体または列をロックしないため、スキーマのアップデート中にデータベースへのデータの書き込みを続けることができます。

列の追加

  1. projects.instances.databases.updateDdl をクリックします。
  2. [database] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db
    
  3. [Request body] で以下のように入力します。

    {
      "statements": [
        "ALTER TABLE Albums ADD COLUMN MarketingBudget INT64"
      ]
    }
    

    statements 配列にはスキーマを定義する DDL ステートメントが含まれます。

  4. [実行] をクリックします。この処理は完了まで数分かかることがあります。これは REST 呼び出しがレスポンスを返した後であっても同様です。レスポンスで長時間実行オペレーションが返されます。これをクエリするとステータスを確認できます。

新しい列へのデータの書き込み

次のコードは、新しい列にデータを書き込みます。MarketingBudget の値を、キーが Albums(1, 1) の行は 100000 に、キーが Albums(2, 2) の行は 500000 に設定します。

  1. projects.instances.databases.sessions.commit をクリックします。
  2. [session] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (この値はセッションの作成時に取得します)

  3. [Request body] で以下のように入力します。

    {
      "singleUseTransaction": {
        "readWrite": {}
      },
      "mutations": [
        {
          "update": {
            "table": "Albums",
            "columns": [
              "SingerId",
              "AlbumId",
              "MarketingBudget"
            ],
            "values": [
              [
                "1",
                "1",
                "100000"
              ],
              [
                "2",
                "2",
                "500000"
              ]
            ]
          }
        }
      ]
    }
    
  4. [実行] をクリックします。レスポンスに commit タイムスタンプが表示されます。

SQL クエリまたは読み取り呼び出しを実行して、書き込んだばかりの値を取得することもできます。

クエリを実行する方法を次に示します。

  1. projects.instances.databases.sessions.executeSql をクリックします。
  2. [session] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (この値はセッションの作成時に取得します)

  3. [Request body] で以下のように入力します。

    {
      "sql": "SELECT SingerId, AlbumId, MarketingBudget FROM Albums"
    }
    
  4. [実行] をクリックします。レスポンスの中に、更新された MarketingBudget 値を含む 2 行が次のように表示されます。

    "rows": [
      [
        "1",
        "1",
        "100000"
      ],
      [
        "1",
        "2",
        null
      ],
      [
        "2",
        "1",
        null
      ],
      [
        "2",
        "2",
        "500000"
      ],
      [
        "2",
        "3",
        null
      ]
    ]
    

セカンダリ インデックスの使用

Albums から AlbumTitle の値が特定の範囲内にある行すべてを取得すると仮定します。SQL ステートメントまたは読み取り呼び出しを使用して AlbumTitle 列からすべての値を読み取り、基準を満たしていない行を破棄することもできますが、このようなテーブル全体のスキャンは割高です(特に、行数が多いテーブルの場合)。代わりに、テーブルにセカンダリ インデックスを作成することにより、主キー以外の列を検索するときの行の取得速度を上げることができます。

既存のテーブルにセカンダリ インデックスを追加するには、スキーマの更新が必要です。他のスキーマの更新と同様に、Spanner ではデータベースがトラフィックの処理を継続している間にインデックスを追加できます。Spanner では、インデックスに既存のデータが自動的にバックフィルされます。バックフィルには数分かかることがありますが、このプロセスの間に、データベースをオフラインにしたり、特定のテーブルや列への書き込みを控えたりする必要はありません。詳細については、インデックスのバックフィリングをご覧ください。

セカンダリ インデックスを追加すると、インデックス効果で実行速度が上がりそうな SQL クエリに対して Spanner ではそのセカンダリ インデックスが自動的に使用されるようになります。読み取りインターフェースを使用する場合は、使用するインデックスを指定する必要があります。

セカンダリ インデックスの追加

インデックスを追加するには、updateDdl を使用します。

  1. projects.instances.databases.updateDdl をクリックします。
  2. [database] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db
    
  3. [Request body] で以下のように入力します。

    {
      "statements": [
        "CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)"
      ]
    }
    
  4. [Execute] をクリックします。この処理は完了まで数分かかることがあります。これは REST 呼び出しがレスポンスを返した後であっても同様です。レスポンスで長時間実行オペレーションが返されます。これをクエリするとステータスを確認できます。

インデックスを使用したクエリ

  1. projects.instances.databases.sessions.executeSql をクリックします。
  2. [session] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (この値はセッションの作成時に取得します)

  3. [Request body] で以下のように入力します。

    {
      "sql": "SELECT AlbumId, AlbumTitle, MarketingBudget FROM Albums WHERE AlbumTitle >= 'Aardvark' AND AlbumTitle < 'Goo'"
    }
    
  4. [実行] をクリックします。レスポンスの中に次のような行が表示されます。

    "rows": [
      [
        "2",
        "Go, Go, Go",
        null
      ],
      [
        "2",
        "Forever Hold Your Peace",
        "500000"
      ]
    ]
    

インデックスを使用した読み取り

  1. projects.instances.databases.sessions.read をクリックします。
  2. [session] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (この値はセッションの作成時に取得します)

  3. [Request body] で以下のように入力します。

    {
      "table": "Albums",
      "columns": [
        "AlbumId",
        "AlbumTitle"
      ],
      "keySet": {
        "all": true
      },
      "index": "AlbumsByAlbumTitle"
    }
    
  4. [実行] をクリックします。レスポンスの中に次のような行が表示されます。

    "rows": [
      [
        "2",
        "Forever Hold Your Peace"
      ],
      [
        "2",
        "Go, Go, Go"
      ],
      [
        "1",
        "Green"
      ],
      [
        "3",
        "Terrified"
      ],
      [
        "1",
        "Total Junk"
      ]
    ]
    

STORING 句を使用したインデックスの追加

上記の読み取り例では、MarketingBudget 列の読み取りが含まれていませんでした。これは、Spanner の読み取りインターフェースが、インデックスとデータテーブルを結合してインデックスに格納されていない値を検索する機能をサポートしていないためです。

MarketingBudget のコピーをインデックスに格納する AlbumsByAlbumTitle の代替定義を作成します。

STORING インデックスを追加するには、updateDdl を使用します。

  1. projects.instances.databases.updateDdl をクリックします。
  2. [database] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db
    
  3. [Request body] で以下のように入力します。

    {
      "statements": [
        "CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) STORING (MarketingBudget)"
      ]
    }
    
  4. [Execute] をクリックします。この処理は完了まで数分かかることがあります。これは REST 呼び出しがレスポンスを返した後であっても同様です。レスポンスで長時間実行オペレーションが返されます。これをクエリするとステータスを確認できます。

これで、インデックス AlbumsByAlbumTitle2 から AlbumIdAlbumTitleMarketingBudget 列をすべて取得する読み取りを実行できるようになりました。

  1. projects.instances.databases.sessions.read をクリックします。
  2. [session] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (この値はセッションの作成時に取得します)

  3. [Request body] で以下のように入力します。

    {
      "table": "Albums",
      "columns": [
        "AlbumId",
        "AlbumTitle",
        "MarketingBudget"
      ],
      "keySet": {
        "all": true
      },
      "index": "AlbumsByAlbumTitle2"
    }
    
  4. [実行] をクリックします。レスポンスの中に次のような行が表示されます。

    "rows": [
      [
        "2",
        "Forever Hold Your Peace",
        "500000"
      ],
      [
        "2",
        "Go, Go, Go",
        null
      ],
      [
        "1",
        "Green",
        null
      ],
      [
        "3",
        "Terrified",
        null
      ],
      [
        "1",
        "Total Junk",
        "100000"
      ]
    ]
    

読み取り専用トランザクションを使用したデータを取得する

同じタイムスタンプで複数の読み取りを実行する場合について考えます。読み取り専用トランザクションはトランザクションの commit 履歴の一貫性のあるプレフィックスを監視しているので、アプリケーションは常に一貫性のあるデータを取得できます。

読み取り専用トランザクションの作成

  1. projects.instances.databases.sessions.beginTransaction をクリックします。
  2. [session] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    
  3. [Request body] で以下のように入力します。

    {
      "options": {
        "readOnly": {}
      }
    }
    
  4. [Execute] をクリックします。

  5. 作成したトランザクションの ID がレスポンスに表示されます。

この読み取り専用トランザクションを使用して、一貫したタイムスタンプでデータを取得できます。これは、この読み取り専用トランザクションの作成後にデータが変更されている場合でも同様です。

読み取り専用トランザクションを使用したクエリの実行

  1. projects.instances.databases.sessions.executeSql をクリックします。
  2. [session] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (この値はセッションの作成時に取得します)

  3. [Request body] で以下のように入力します。

    {
      "sql": "SELECT SingerId, AlbumId, AlbumTitle FROM Albums",
      "transaction": {
        "id": "[TRANSACTION_ID]"
      }
    }
    
  4. [実行] をクリックします。レスポンスに次のような行が表示されます。

    "rows": [
      [
        "2",
        "2",
        "Forever Hold Your Peace"
      ],
      [
        "1",
        "2",
        "Go, Go, Go"
      ],
      [
        "2",
        "1",
        "Green"
      ],
      [
        "2",
        "3",
        "Terrified"
      ],
      [
        "1",
        "1",
        "Total Junk"
      ]
    ]
    

読み取り専用トランザクションを使用した読み取り

  1. projects.instances.databases.sessions.read をクリックします。
  2. [session] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db/sessions/[SESSION]
    

    (この値はセッションの作成時に取得します)

  3. [Request body] で以下のように入力します。

    {
      "table": "Albums",
      "columns": [
        "SingerId",
        "AlbumId",
        "AlbumTitle"
      ],
      "keySet": {
        "all": true
      },
      "transaction": {
        "id": "[TRANSACTION_ID]"
      }
    }
    
  4. [実行] をクリックします。レスポンスに次のような行が表示されます。

    "rows": [
      [
        "1",
        "1",
        "Total Junk"
      ],
      [
        "1",
        "2",
        "Go, Go, Go"
      ],
      [
        "2",
        "1",
        "Green"
      ],
      [
        "2",
        "2",
        "Forever Hold Your Peace"
      ],
      [
        "2",
        "3",
        "Terrified"
      ]
    ]
    

Spanner は読み書きトランザクションもサポートしています。このトランザクションでは、ある論理的な時点で一連の読み取りと書き込みをアトミックに実行します。詳細については、読み取り / 書き込みトランザクションをご覧ください。(試してみましょう機能は読み取り / 書き込みトランザクションのデモンストレーションには適切ではありません。)

クリーンアップ

このチュートリアルで使用したリソースについて Google Cloud アカウントに課金されないようにするため、作成したデータベースとインスタンスを削除します。

データベースの削除

  1. projects.instances.databases.dropDatabase をクリックします。
  2. [name] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance/databases/example-db
    
  3. [Execute] をクリックします。

インスタンスの削除

  1. projects.instances.delete をクリックします。
  2. [name] に以下のように入力します。

    projects/[PROJECT_ID]/instances/test-instance
    
  3. [Execute] をクリックします。

次のステップ