创建和管理数据库

本页面介绍如何管理 Spanner 数据库,包括如何创建数据库、修改数据库选项和删除数据库。如需了解如何更新数据库架构,请参阅进行架构更新

如需练习创建数据库并使用示例数据加载该数据库,请参阅您的第一个数据库 Codelab

创建数据库

以下示例展示了如何在现有实例中创建数据库。

对于 GoogleSQL 方言数据库,您可以在创建数据库时或创建数据库之后定义数据库架构。对于 PostgreSQL 方言数据库,您必须在创建后定义架构。

架构使用数据库定义语言进行定义,该语言针对 GoogleSQLPostgreSQL 进行了介绍。如需详细了解如何创建和更新架构,请参阅以下链接:

创建数据库后,您可以通过启用数据库删除保护来保护对您的应用和服务至关重要的数据库。如需了解详情,请参阅防止意外删除数据库

控制台

  1. 转到 Google Cloud 控制台中的实例页面。

    实例

  2. 选择要在其中创建数据库的实例。

  3. 点击创建数据库

  4. 输入以下值:

    • 要在 Google Cloud 控制台中显示的数据库名称
    • 用于此数据库的方言
    • 对于 GoogleSQL 方言数据库,可以选择提供一组用于定义架构的 DDL 语句。使用 DDL 模板预填充常用元素。如果您的 DDL 语句存在错误,则 Google Cloud 控制台会在您尝试创建数据库时返回错误。
    • (可选)选择要用于此数据库的客户管理的加密密钥
  5. 点击创建以创建数据库。

gcloud

使用 gcloud spanner databases create 命令。

gcloud spanner databases create DATABASE \
  --instance=INSTANCE \
  [--async] \
  [--database-dialect=DATABASE_DIALECT] \
  [--ddl=DDL] \
  [--ddl-file=DDL_FILE] \
  [--kms-key=KMS_KEY : --kms-keyring=KMS_KEYRING --kms-location=KMS_LOCATION --kms-project=KMS_PROJECT] \
  [GCLOUD_WIDE_FLAG …]

以下选项为必需:

DATABASE
数据库的 ID 或数据库的完全限定标识符。如果指定完全限定标识符,则可以省略 --instance 标志。
--instance=INSTANCE
数据库的 Spanner 实例。

以下选项为可选:

--async
立即返回,无需等待操作完成。
--database-dialect=DATABASE_DIALECT
Spanner 数据库的 SQL 方言。必须为以下项之一:POSTGRESQLGOOGLE_STANDARD_SQL
--ddl=DDL
要在新创建的数据库内运行的 DDL(数据定义语言)语句(以分号分隔)。如果任何语句中存在错误,则不会创建数据库。如果设置了 --ddl_file,则忽略此标志。PostgreSQL 方言数据库不支持。
--ddl-file=DDL_FILE
文件的路径,该文件包含将在新创建的数据库中运行的以英文分号分隔的 DDL(数据定义语言)语句。如果任何语句中存在错误,则不会创建数据库。如果设置了 --ddl_file,系统会忽略 --ddl。PostgreSQL 方言数据库不支持。

如果您要指定在创建数据库时使用的 Cloud Key Management Service 密钥,请添加以下选项:

--kms-key=KMS_KEY
密钥的 ID 或密钥的完全限定标识符。

如果指定了该组中的任何其他参数,则必须指定此标志。如果提供了完全限定的标识符,则可省略其他参数。

--kms-keyring=KMS_KEYRING
密钥的 Cloud KMS 密钥环 ID。
--kms-location=KMS_LOCATION
密钥的 Google Cloud 位置。
--kms-project=KMS_PROJECT
密钥的 Google Cloud 项目 ID。

客户端 (GoogleSQL)

C++

如需了解如何安装和使用 Spanner 客户端库,请参阅 Spanner 客户端库

如需向 Spanner 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证

void CreateDatabase(google::cloud::spanner_admin::DatabaseAdminClient client,
                    std::string const& project_id,
                    std::string const& instance_id,
                    std::string const& database_id) {
  google::cloud::spanner::Database database(project_id, instance_id,
                                            database_id);
  google::spanner::admin::database::v1::CreateDatabaseRequest request;
  request.set_parent(database.instance().FullName());
  request.set_create_statement("CREATE DATABASE `" + database.database_id() +
                               "`");
  request.add_extra_statements(R"""(
      CREATE TABLE Singers (
          SingerId   INT64 NOT NULL,
          FirstName  STRING(1024),
          LastName   STRING(1024),
          SingerInfo BYTES(MAX),
          FullName   STRING(2049)
              AS (ARRAY_TO_STRING([FirstName, LastName], " ")) STORED
      ) PRIMARY KEY (SingerId))""");
  request.add_extra_statements(R"""(
      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)""");
  auto db = client.CreateDatabase(request).get();
  if (!db) throw std::move(db).status();
  std::cout << "Database " << db->name() << " created.\n";
}

Go

如需了解如何安装和使用 Spanner 客户端库,请参阅 Spanner 客户端库

如需向 Spanner 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证

import (
	"context"
	"fmt"
	"io"
	"regexp"

	database "cloud.google.com/go/spanner/admin/database/apiv1"
	adminpb "google.golang.org/genproto/googleapis/spanner/admin/database/v1"
)

func createDatabase(ctx context.Context, w io.Writer, db string) error {
	matches := regexp.MustCompile("^(.*)/databases/(.*)$").FindStringSubmatch(db)
	if matches == nil || len(matches) != 3 {
		return fmt.Errorf("Invalid database id %s", db)
	}

	adminClient, err := database.NewDatabaseAdminClient(ctx)
	if err != nil {
		return err
	}
	defer adminClient.Close()

	op, err := adminClient.CreateDatabase(ctx, &adminpb.CreateDatabaseRequest{
		Parent:          matches[1],
		CreateStatement: "CREATE DATABASE `" + matches[2] + "`",
		ExtraStatements: []string{
			`CREATE TABLE Singers (
				SingerId   INT64 NOT NULL,
				FirstName  STRING(1024),
				LastName   STRING(1024),
				SingerInfo BYTES(MAX),
				FullName   STRING(2048) AS (
					ARRAY_TO_STRING([FirstName, LastName], " ")
				) STORED
			) 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`,
		},
	})
	if err != nil {
		return err
	}
	if _, err := op.Wait(ctx); err != nil {
		return err
	}
	fmt.Fprintf(w, "Created database [%s]\n", db)
	return nil
}

Java

如需了解如何安装和使用 Spanner 客户端库,请参阅 Spanner 客户端库

如需向 Spanner 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证


import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
import com.google.common.collect.ImmutableList;
import com.google.spanner.admin.database.v1.CreateDatabaseRequest;
import com.google.spanner.admin.database.v1.Database;
import java.io.IOException;
import java.util.concurrent.ExecutionException;

public class CreateDatabaseWithDefaultLeaderSample {

  static void createDatabaseWithDefaultLeader() throws IOException {
    // TODO(developer): Replace these variables before running the sample.
    final String instanceName = "projects/my-project/instances/my-instance-id";
    final String databaseId = "my-database-name";
    final String defaultLeader = "my-default-leader";
    createDatabaseWithDefaultLeader(instanceName, databaseId, defaultLeader);
  }

  static void createDatabaseWithDefaultLeader(String instanceName, String databaseId,
      String defaultLeader) throws IOException {
    try (DatabaseAdminClient databaseAdminClient = DatabaseAdminClient.create()) {
      Database createdDatabase =
          databaseAdminClient.createDatabaseAsync(
              CreateDatabaseRequest.newBuilder()
                  .setParent(instanceName)
                  .setCreateStatement("CREATE DATABASE `" + databaseId + "`")
                  .addAllExtraStatements(
                      ImmutableList.of("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",
                          "ALTER DATABASE " + "`" + databaseId + "`"
                              + " SET OPTIONS ( default_leader = '" + defaultLeader + "' )"))
                  .build()).get();
      System.out.println("Created database [" + createdDatabase.getName() + "]");
      System.out.println("\tDefault leader: " + createdDatabase.getDefaultLeader());
    } catch (ExecutionException e) {
      // If the operation failed during execution, expose the cause.
      throw (SpannerException) e.getCause();
    } catch (InterruptedException e) {
      // Throw when a thread is waiting, sleeping, or otherwise occupied,
      // and the thread is interrupted, either before or during the activity.
      throw SpannerExceptionFactory.propagateInterrupt(e);
    }
  }
}

Node.js

如需了解如何安装和使用 Spanner 客户端库,请参阅 Spanner 客户端库

如需向 Spanner 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// const projectId = 'my-project-id';
// const instanceId = 'my-instance-id';
// const databaseId = 'my-database-id';
// const defaultLeader = 'my-default-leader'; example: 'asia-northeast1'

// Imports the Google Cloud client library
const {Spanner} = require('@google-cloud/spanner');

// creates a client
const spanner = new Spanner({
  projectId: projectId,
});

// Gets a reference to a Cloud Spanner Database Admin Client object
const databaseAdminClient = spanner.getDatabaseAdminClient();

async function createDatabaseWithDefaultLeader() {
  // Create a new database with an extra statement which will alter the
  // database after creation to set the default leader.
  console.log(
    `Creating database ${databaseAdminClient.databasePath(
      projectId,
      instanceId,
      databaseId
    )}.`
  );
  const createSingersTableStatement = `
    CREATE TABLE Singers (
      SingerId   INT64 NOT NULL,
      FirstName  STRING(1024),
      LastName   STRING(1024),
      SingerInfo BYTES(MAX)
    ) PRIMARY KEY (SingerId)`;
  const createAlbumsStatement = `
    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`;

  // Default leader is one of the possible values in the leaderOptions field of the
  // instance config of the instance where the database is created.
  const setDefaultLeaderStatement = `
    ALTER DATABASE \`${databaseId}\`
    SET OPTIONS (default_leader = '${defaultLeader}')`;

  const [operation] = await databaseAdminClient.createDatabase({
    createStatement: 'CREATE DATABASE `' + databaseId + '`',
    extraStatements: [
      createSingersTableStatement,
      createAlbumsStatement,
      setDefaultLeaderStatement,
    ],
    parent: databaseAdminClient.instancePath(projectId, instanceId),
  });

  console.log(`Waiting for creation of ${databaseId} to complete...`);
  await operation.promise();
  console.log(
    `Created database ${databaseId} with default leader ${defaultLeader}.`
  );
}
createDatabaseWithDefaultLeader();

PHP

如需了解如何安装和使用 Spanner 客户端库,请参阅 Spanner 客户端库

如需向 Spanner 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证

use Google\Cloud\Spanner\Admin\Database\V1\Client\DatabaseAdminClient;
use Google\Cloud\Spanner\Admin\Database\V1\CreateDatabaseRequest;

/**
 * Creates a database and tables for sample data.
 * Example:
 * ```
 * create_database($instanceId, $databaseId);
 * ```
 *
 * @param string $projectId The Google Cloud project ID.
 * @param string $instanceId The Spanner instance ID.
 * @param string $databaseId The Spanner database ID.
 */
function create_database(string $projectId, string $instanceId, string $databaseId): void
{
    $databaseAdminClient = new DatabaseAdminClient();
    $instance = $databaseAdminClient->instanceName($projectId, $instanceId);

    $operation = $databaseAdminClient->createDatabase(
        new CreateDatabaseRequest([
            'parent' => $instance,
            'create_statement' => sprintf('CREATE DATABASE `%s`', $databaseId),
            'extra_statements' => [
                'CREATE TABLE Singers (' .
                'SingerId     INT64 NOT NULL,' .
                'FirstName    STRING(1024),' .
                'LastName     STRING(1024),' .
                'SingerInfo   BYTES(MAX),' .
                'FullName     STRING(2048) AS' .
                '(ARRAY_TO_STRING([FirstName, LastName], " ")) STORED' .
                ') 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'
            ]
        ])
    );

    print('Waiting for operation to complete...' . PHP_EOL);
    $operation->pollUntilComplete();

    printf('Created database %s on instance %s' . PHP_EOL,
        $databaseId, $instanceId);
}

Python

如需了解如何安装和使用 Spanner 客户端库,请参阅 Spanner 客户端库

如需向 Spanner 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证

def create_database(instance_id, database_id):
    """Creates a database and tables for sample data."""
    from google.cloud.spanner_admin_database_v1.types import \
        spanner_database_admin

    spanner_client = spanner.Client()
    database_admin_api = spanner_client.database_admin_api

    request = spanner_database_admin.CreateDatabaseRequest(
        parent=database_admin_api.instance_path(spanner_client.project, instance_id),
        create_statement=f"CREATE DATABASE `{database_id}`",
        extra_statements=[
            """CREATE TABLE Singers (
            SingerId     INT64 NOT NULL,
            FirstName    STRING(1024),
            LastName     STRING(1024),
            SingerInfo   BYTES(MAX),
            FullName   STRING(2048) AS (
                ARRAY_TO_STRING([FirstName, LastName], " ")
            ) STORED
        ) 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""",
        ],
    )

    operation = database_admin_api.create_database(request=request)

    print("Waiting for operation to complete...")
    database = operation.result(OPERATION_TIMEOUT_SECONDS)

    print(
        "Created database {} on instance {}".format(
            database.name,
            database_admin_api.instance_path(spanner_client.project, instance_id),
        )
    )

Ruby

如需了解如何安装和使用 Spanner 客户端库,请参阅 Spanner 客户端库

如需向 Spanner 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为本地开发环境设置身份验证

# project_id  = "Your Google Cloud project ID"
# instance_id = "Your Spanner instance ID"
# database_id = "Your Spanner database ID"

require "google/cloud/spanner"
require "google/cloud/spanner/admin/database"

database_admin_client = Google::Cloud::Spanner::Admin::Database.database_admin

instance_path = database_admin_client.instance_path project: project_id, instance: instance_id

job = database_admin_client.create_database parent: instance_path,
                                            create_statement: "CREATE DATABASE `#{database_id}`",
                                            extra_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"
                                            ]

puts "Waiting for create database operation to complete"

job.wait_until_done!

puts "Created database #{database_id} on instance #{instance_id}"

更新数据库架构或选项

您可以使用 DDL 语句更新数据库架构和选项。

例如,如需向表添加列,请使用以下 DDL 语句:

GoogleSQL

ALTER TABLE Songwriters ADD COLUMN Publisher STRING(10);

PostgreSQL

ALTER TABLE Songwriters ADD COLUMN Publisher VARCHAR(10);

如需更新查询优化器版本,请使用以下 DDL 语句:

GoogleSQL

ALTER DATABASE Music SET OPTIONS(optimizer_version=null);

PostgreSQL

ALTER DATABASE DB-NAME SET spanner.optimizer_version TO DEFAULT;

如需详细了解支持的选项,请参阅适用于 GoogleSQLPostgreSQLALTER DATABASE DDL 参考文档。

如需了解架构更新,请参阅进行架构更新

控制台

  1. 转到 Google Cloud 控制台中的实例页面。

    实例

  2. 选择包含要更改的数据库的实例。

  3. 选择数据库。

  4. 点击 Spanner Studio

  5. 点击 新标签页,或使用空的编辑器标签页。然后,输入要应用的 DDL 语句。

  6. 点击运行以应用更新。如果您的 DDL 中存在错误,Google Cloud 控制台会返回错误,并且数据库不会发生变化。

gcloud

如需使用 gcloud 命令行工具更改数据库,请使用 gcloud spanner databases ddl update

gcloud spanner databases ddl update \
(DATABASE : --instance=INSTANCE) \
[--async] \
[--ddl=DDL] \
[--ddl-file=DDL_FILE] \

如需详细了解可用选项,请参阅 gcloud 参考文档

使用 --ddl 标志或 --ddl-file 标志将数据库更新传递给命令。如果指定了 DDL 文件,系统会忽略 --ddl 标志。

如需了解要包含的 DDL 语句,请参阅适用于 GoogleSQLPostgreSQLALTER DATABASE DDL 参考文档。

DDL

如需了解详情,请参阅适用于 GoogleSQLPostgreSQLALTER DATABASE DDL 参考文档。

检查架构更新操作的进度

控制台

  1. 在 Spanner 导航菜单中,选择操作标签页。操作页面会显示当前正在运行的操作列表。

  2. 在列表中找到架构操作。如果操作仍在运行,结束时间列中的进度条会显示操作完成的百分比,如下图所示:

进度条显示 98% 的屏幕截图

gcloud

使用 gcloud spanner operations describe 检查操作的进度。

  1. 获取操作 ID:

    gcloud spanner operations list --instance=INSTANCE-NAME \
    --database=DATABASE-NAME --type=DATABASE_UPDATE_DDL
    

    请替换以下内容:

    • INSTANCE-NAME 替换为 Spanner 实例名称。
    • DATABASE-NAME 替换为数据库的名称。
  2. 运行 gcloud spanner operations describe

    gcloud spanner operations describe OPERATION_ID\
    --instance=INSTANCE-NAME \
    --database=DATABASE-NAME
    

    请替换以下内容:

    • OPERATION-ID:您要检查的操作的操作 ID。
    • INSTANCE-NAME:Spanner 实例名称。
    • DATABASE-NAME:Spanner 数据库名称。

    输出中的 progress 部分显示操作完成百分比。输出类似于以下内容:

    done: true
    metadata:
    ...
      progress:
      - endTime: '2022-03-01T00:28:06.691403Z'
        progressPercent: 100
        startTime: '2022-03-01T00:28:04.221401Z'
      - endTime: '2022-03-01T00:28:17.624588Z'
        startTime: '2022-03-01T00:28:06.691403Z'
        progressPercent: 100
    ...
    

REST v1

  1. 获取操作 ID:

    gcloud spanner operations list --instance=INSTANCE-NAME \
    --database=DATABASE-NAME --type=DATABASE_UPDATE_DDL
    

    请替换以下内容:

    • INSTANCE-NAME 替换为 Spanner 实例名称。
    • DATABASE-NAME 替换为数据库名称。
  2. 查看操作的进度。

    在使用任何请求数据之前,请先进行以下替换:

    • PROJECT-ID:项目 ID。
    • INSTANCE-ID:实例 ID。
    • DATABASE-ID:数据库 ID。
    • OPERATION-ID:操作 ID。

    HTTP 方法和网址:

    GET https://spanner.googleapis.com/v1/projects/PROJECT-ID/instances/INSTANCE-ID/databases/DATABASE-ID/operations/OPERATION-ID

    如需发送您的请求,请展开以下选项之一:

    您应该收到类似以下内容的 JSON 响应:

    {
    ...
        "progress": [
          {
            "progressPercent": 100,
            "startTime": "2023-05-27T00:52:27.366688Z",
            "endTime": "2023-05-27T00:52:30.184845Z"
          },
          {
            "progressPercent": 100,
            "startTime": "2023-05-27T00:52:30.184845Z",
            "endTime": "2023-05-27T00:52:40.750959Z"
          }
        ],
    ...
      "done": true,
      "response": {
        "@type": "type.googleapis.com/google.protobuf.Empty"
      }
    }
    
    

如果操作花费的时间过长,您可以取消操作。如需了解详情,请参阅取消长时间运行的数据库操作

删除数据库

删除数据库将会永久移除该数据库及其所有数据。数据库删除操作无法撤消。如果某个数据库启用了数据库删除保护,那么您必须先停用其删除保护,然后才能删除该数据库。

删除数据库时,现有备份不会被删除。如需了解详情,请参阅备份和恢复

控制台

  1. 转到 Google Cloud 控制台中的实例页面。

    实例

  2. 选择要删除的数据库所在的实例。

  3. 选择数据库。

  4. 点击删除数据库。系统会显示确认消息。

  5. 输入数据库名称,然后点击删除

gcloud

如需使用 gcloud 命令行工具删除数据库,请使用 gcloud spanner databases delete

gcloud spanner databases delete \
  (DATABASE : --instance=INSTANCE)

以下选项为必需:

DATABASE
数据库的 ID 或数据库的完全限定标识符。如果提供了完全限定标识符,则应省略 --instance 标志。
--instance=INSTANCE
数据库的 Spanner 实例。

如需了解详情,请参阅 gcloud 参考文档

DDL

DDL 不支持数据库删除语法。

后续步骤