Spanner 使用入门 (Python)


目标

本教程将介绍如何使用 Python 版 Cloud Spanner 客户端库完成以下步骤:

  • 创建 Spanner 实例和数据库。
  • 写入、读取数据库中的数据和对数据执行 SQL 查询。
  • 更新数据库架构。
  • 使用读写事务更新数据。
  • 向数据库添加二级索引。
  • 使用索引来读取数据和对数据执行 SQL 查询。
  • 使用只读事务检索数据。

费用

本教程使用 Spanner,它是Google Cloud的收费组件。如需了解使用 Spanner 的费用,请参阅价格

准备工作

完成设置中介绍的步骤,包括创建和设置默认 Google Cloud 项目、启用结算功能、启用 Cloud Spanner API 以及设置 OAuth 2.0 来获取身份验证凭据以使用 Cloud Spanner API。

尤其要确保运行 gcloud auth application-default login,以便使用身份验证凭据设置本地开发环境。

准备本地 Python 环境

  1. 按照设置 Python 开发环境中的说明进行操作。

  2. 将示例应用代码库克隆到本地机器:

    git clone https://github.com/googleapis/python-spanner 

    或者,也可以下载该示例的 zip 文件并将其解压缩。

  3. 切换到包含 Spanner 示例代码的目录:

    cd python-spanner/samples/samples 
  4. 创建一个独立的 Python 环境,并安装依赖项:

    virtualenv env source env/bin/activate pip install -r requirements.txt 

创建实例

在首次使用 Spanner 时,必须创建一个实例,实例是 Spanner 数据库使用的资源分配单位。创建实例时,请选择一个实例配置(决定数据的存储位置),同时选择要使用的节点数(决定实例中服务资源和存储资源的数量)。

执行以下命令,在区域 us-central1 中创建具有 1 个节点的 Spanner 实例:

gcloud spanner instances create test-instance --config=regional-us-central1 \     --description="Test Instance" --nodes=1 

请注意,此命令将创建一个具有以下特征的实例:

  • 实例 ID 为 test-instance
  • 显示名为 Test Instance
  • 实例配置为 regional-us-central1(单区域配置将数据存储在单个区域中,而多区域配置则将数据分布在多个区域中。如需了解详情,请参阅实例简介。)
  • 节点数为 1(node_count 对应于实例中数据库可用的服务资源和存储资源的数量。如需了解详情,请参阅节点和处理单元。)

您应该会看到:

Creating instance...done. 

浏览示例文件

示例仓库包含一个示例,展示了如何将 Spanner 与 Python 搭配使用。

请浏览 snippets.py 文件,其中说明了如何使用 Spanner。代码展示了如何创建和使用新数据库。数据使用架构和数据模型页面中显示的示例架构。

创建数据库

GoogleSQL

python snippets.py test-instance --database-id example-db create_database 

PostgreSQL

python pg_snippets.py test-instance --database-id example-db create_database 

您应该会看到:

Created database example-db on instance test-instance 
以下代码会创建一个数据库以及该数据库中的两个表。

GoogleSQL

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),         )     )  

PostgreSQL

def create_database(instance_id, database_id):     """Creates a PostgreSql 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}"',         database_dialect=DatabaseDialect.POSTGRESQL,     )      operation = database_admin_api.create_database(request=request)      print("Waiting for operation to complete...")     database = operation.result(OPERATION_TIMEOUT_SECONDS)      create_table_using_ddl(database.name)     print("Created database {} on instance {}".format(database_id, instance_id))   def create_table_using_ddl(database_name):     from google.cloud.spanner_admin_database_v1.types import \         spanner_database_admin      spanner_client = spanner.Client()     request = spanner_database_admin.UpdateDatabaseDdlRequest(         database=database_name,         statements=[             """CREATE TABLE Singers (   SingerId   bigint NOT NULL,   FirstName  character varying(1024),   LastName   character varying(1024),   SingerInfo bytea,   FullName   character varying(2048)     GENERATED ALWAYS AS (FirstName || ' ' || LastName) STORED,   PRIMARY KEY (SingerId)   )""",             """CREATE TABLE Albums (   SingerId     bigint NOT NULL,   AlbumId      bigint NOT NULL,   AlbumTitle   character varying(1024),   PRIMARY KEY (SingerId, AlbumId)   ) INTERLEAVE IN PARENT Singers ON DELETE CASCADE""",         ],     )     operation = spanner_client.database_admin_api.update_database_ddl(request)     operation.result(OPERATION_TIMEOUT_SECONDS)  

下一步是将数据写入数据库。

创建数据库客户端

您必须先创建一个 Client,然后才能执行读写操作。您可以将 Client 视为数据库连接:您与 Spanner 的所有交互都必须通过 Client 进行。通常,您可以在应用启动时创建 Client,然后重复使用该 Client 来读取、写入和执行事务。以下代码演示了如何创建客户端。

# Imports the Google Cloud Client Library. from google.cloud import spanner  # Your Cloud Spanner instance ID. # instance_id = "my-instance-id" # # Your Cloud Spanner database ID. # database_id = "my-database-id" # Instantiate a client. spanner_client = spanner.Client()  # Get a Cloud Spanner instance by ID. instance = spanner_client.instance(instance_id)  # Get a Cloud Spanner database by ID. database = instance.database(database_id)  # Execute a simple SQL statement. with database.snapshot() as snapshot:     results = snapshot.execute_sql("SELECT 1")      for row in results:         print(row)

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

使用 DML 写入数据

您可以在读写事务中使用数据操纵语言 (DML) 插入数据。

使用 execute_update() 方法来执行 DML 语句。

# instance_id = "your-spanner-instance" # database_id = "your-spanner-db-id" spanner_client = spanner.Client() instance = spanner_client.instance(instance_id) database = instance.database(database_id)  def insert_singers(transaction):     row_ct = transaction.execute_update(         "INSERT INTO Singers (SingerId, FirstName, LastName) VALUES "         "(12, 'Melissa', 'Garcia'), "         "(13, 'Russell', 'Morales'), "         "(14, 'Jacqueline', 'Long'), "         "(15, 'Dylan', 'Shaw')"     )     print("{} record(s) inserted.".format(row_ct))  database.run_in_transaction(insert_singers)

使用 insert_with_dml 参数运行示例。

python snippets.py test-instance --database-id example-db insert_with_dml 

您应该会看到:

4 record(s) inserted. 

使用变更写入数据

您还可以使用变更插入数据。

您可以使用 Batch 对象来写入数据。Batch 对象是用于变更操作的容器。变更表示插入、更新和删除等一系列操作,Spanner 将这些操作以原子方式应用于 Spanner 数据库中不同的行和表。

Batch 类中的 insert() 方法用于向批处理添加一个或多个插入变更操作。单个批处理中的所有变更均以原子方式应用。

此代码演示了如何使用变更写入数据:

def insert_data(instance_id, database_id):     """Inserts sample data into the given database.      The database and table must already exist and can be created using     `create_database`.     """     spanner_client = spanner.Client()     instance = spanner_client.instance(instance_id)     database = instance.database(database_id)      with database.batch() as batch:         batch.insert(             table="Singers",             columns=("SingerId", "FirstName", "LastName"),             values=[                 (1, "Marc", "Richards"),                 (2, "Catalina", "Smith"),                 (3, "Alice", "Trentor"),                 (4, "Lea", "Martin"),                 (5, "David", "Lomond"),             ],         )          batch.insert(             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"),             ],         )      print("Inserted data.")  

使用 insert_data 参数运行示例。

python snippets.py test-instance --database-id example-db insert_data 

您应该会看到:

Inserted data. 

使用 SQL 查询数据

Spanner 支持使用 SQL 接口读取数据,您可以使用 Google Cloud CLI 在命令行中访问该接口,也可以使用 Python 版 Spanner 客户端库以编程方式访问该接口。

在命令行中

执行以下 SQL 语句,读取 Albums 表中所有列的值:

gcloud spanner databases execute-sql example-db --instance=test-instance \     --sql='SELECT SingerId, AlbumId, AlbumTitle FROM Albums' 

结果应为:

SingerId AlbumId AlbumTitle 1        1       Total Junk 1        2       Go, Go, Go 2        1       Green 2        2       Forever Hold Your Peace 2        3       Terrified 

使用 Python 版 Spanner 客户端库

除了在命令行中执行 SQL 语句外,还可以使用 Python 版 Spanner 客户端库以编程方式发出相同的 SQL 语句。

使用 Snapshot 对象的 execute_sql() 方法运行 SQL 查询。如需获取 Snapshot 对象,请在 with 语句中调用 Database 类的 snapshot() 方法。

下面演示了如何发出查询并访问数据:

def query_data(instance_id, database_id):     """Queries sample data from the database using SQL."""     spanner_client = spanner.Client()     instance = spanner_client.instance(instance_id)     database = instance.database(database_id)      with database.snapshot() as snapshot:         results = snapshot.execute_sql(             "SELECT SingerId, AlbumId, AlbumTitle FROM Albums"         )          for row in results:             print("SingerId: {}, AlbumId: {}, AlbumTitle: {}".format(*row))  

使用 query_data 参数运行示例。

python snippets.py test-instance --database-id example-db query_data 

您应该会看到以下结果:

SingerId: 2, AlbumId: 2, AlbumTitle: Forever Hold Your Peace SingerId: 1, AlbumId: 2, AlbumTitle: Go, Go, Go SingerId: 2, AlbumId: 1, AlbumTitle: Green SingerId: 2, AlbumId: 3, AlbumTitle: Terrified SingerId: 1, AlbumId: 1, AlbumTitle: Total Junk 

使用 SQL 参数进行查询

如果您的应用具有频繁执行的查询,您可以通过将其参数化来提高其性能。生成的参数查询可以缓存下来并重复使用,这样做可以降低编译开销。如需了解详情,请参阅使用查询参数来加快频繁执行的查询的运行速度

以下示例演示了如何在 WHERE 子句中使用参数来查询包含特定 LastName 值的记录。

# instance_id = "your-spanner-instance" # database_id = "your-spanner-db-id" spanner_client = spanner.Client() instance = spanner_client.instance(instance_id) database = instance.database(database_id)  with database.snapshot() as snapshot:     results = snapshot.execute_sql(         "SELECT SingerId, FirstName, LastName FROM Singers "         "WHERE LastName = @lastName",         params={"lastName": "Garcia"},         param_types={"lastName": spanner.param_types.STRING},     )      for row in results:         print("SingerId: {}, FirstName: {}, LastName: {}".format(*row))

使用 query_data_with_parameter 参数运行示例。

python snippets.py test-instance --database-id example-db query_data_with_parameter 

您应该会看到以下结果:

SingerId: 12, FirstName: Melissa, LastName: Garcia 

使用读取 API 读取数据

除了 Spanner 的 SQL 接口外,Spanner 还支持读取接口。

使用 Snapshot 对象的 read() 方法从数据库中读取行。如需获取 Snapshot 对象,请在 with 语句中调用 Database 类的 snapshot() 方法。使用 KeySet 对象定义要读取的键和键范围的集合。

下面演示了如何读取数据:

def read_data(instance_id, database_id):     """Reads sample data from the database."""     spanner_client = spanner.Client()     instance = spanner_client.instance(instance_id)     database = instance.database(database_id)      with database.snapshot() as snapshot:         keyset = spanner.KeySet(all_=True)         results = snapshot.read(             table="Albums", columns=("SingerId", "AlbumId", "AlbumTitle"), keyset=keyset         )          for row in results:             print("SingerId: {}, AlbumId: {}, AlbumTitle: {}".format(*row))  

使用 read_data 参数运行示例。

python snippets.py test-instance --database-id example-db read_data 

您看到的输出结果应该类似于以下内容:

SingerId: 1, AlbumId: 1, AlbumTitle: Total Junk SingerId: 1, AlbumId: 2, AlbumTitle: Go, Go, Go SingerId: 2, AlbumId: 1, AlbumTitle: Green SingerId: 2, AlbumId: 2, AlbumTitle: Forever Hold Your Peace SingerId: 2, AlbumId: 3, AlbumTitle: Terrified 

更新数据库架构

假设您需要将名为 MarketingBudget 的新列添加到 Albums 表。向现有表添加新列需要更新数据库架构。Spanner 支持在数据库继续处理流量的同时,对数据库进行架构更新。架构更新不需要使数据库离线,并且不会锁定整个表或列;在架构更新期间,您可以继续将数据写入数据库。如需详细了解支持的架构更新和架构更改性能,请参阅更新架构

添加列

您可以使用 Google Cloud CLI 在命令行中添加列,也可以使用 Python 版 Spanner 客户端库以编程方式添加列。

在命令行中

使用以下 ALTER TABLE 命令向表添加新列:

GoogleSQL

gcloud spanner databases ddl update example-db --instance=test-instance \     --ddl='ALTER TABLE Albums ADD COLUMN MarketingBudget INT64' 

PostgreSQL

gcloud spanner databases ddl update example-db --instance=test-instance \     --ddl='ALTER TABLE Albums ADD COLUMN MarketingBudget BIGINT' 

您应该会看到:

Schema updating...done. 

使用 Python 版 Spanner 客户端库

使用 Database 类的 update_ddl() 方法来修改架构:

def add_column(instance_id, database_id):     """Adds a new column to the Albums table in the example database."""      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.UpdateDatabaseDdlRequest(         database=database_admin_api.database_path(             spanner_client.project, instance_id, database_id         ),         statements=[             "ALTER TABLE Albums ADD COLUMN MarketingBudget INT64",         ],     )      operation = database_admin_api.update_database_ddl(request)      print("Waiting for operation to complete...")     operation.result(OPERATION_TIMEOUT_SECONDS)     print("Added the MarketingBudget column.")  

使用 add_column 参数运行示例。

python snippets.py test-instance --database-id example-db add_column 

您应该会看到:

Added the MarketingBudget column. 

将数据写入新列

以下代码可将数据写入新列。对于 Albums(1, 1) 键控的行,该代码会将 MarketingBudget 设置为 100000;而对于 Albums(2, 2) 键控的行,该代码会将其设置为 500000

def update_data(instance_id, database_id):     """Updates sample data in the database.      This updates the `MarketingBudget` column which must be created before     running this sample. You can add the column by running the `add_column`     sample or by running this DDL statement against your database:          ALTER TABLE Albums ADD COLUMN MarketingBudget INT64      """     spanner_client = spanner.Client()     instance = spanner_client.instance(instance_id)     database = instance.database(database_id)      with database.batch() as batch:         batch.update(             table="Albums",             columns=("SingerId", "AlbumId", "MarketingBudget"),             values=[(1, 1, 100000), (2, 2, 500000)],         )      print("Updated data.")  

使用 update_data 参数运行示例。

python snippets.py test-instance --database-id example-db update_data 

您还可以执行 SQL 查询或读取调用来获取刚才写入的值。

以下是执行查询的代码:

def query_data_with_new_column(instance_id, database_id):     """Queries sample data from the database using SQL.      This sample uses the `MarketingBudget` column. You can add the column     by running the `add_column` sample or by running this DDL statement against     your database:          ALTER TABLE Albums ADD COLUMN MarketingBudget INT64     """     spanner_client = spanner.Client()     instance = spanner_client.instance(instance_id)     database = instance.database(database_id)      with database.snapshot() as snapshot:         results = snapshot.execute_sql(             "SELECT SingerId, AlbumId, MarketingBudget FROM Albums"         )          for row in results:             print("SingerId: {}, AlbumId: {}, MarketingBudget: {}".format(*row))  

如需执行此查询,请使用 query_data_with_new_column 参数运行示例。

python snippets.py test-instance --database-id example-db query_data_with_new_column 

您应该会看到:

SingerId: 2, AlbumId: 2, MarketingBudget: 500000 SingerId: 1, AlbumId: 2, MarketingBudget: None SingerId: 2, AlbumId: 1, MarketingBudget: None SingerId: 2, AlbumId: 3, MarketingBudget: None SingerId: 1, AlbumId: 1, MarketingBudget: 100000 

更新数据

您可以在读写事务中使用 DML 来更新数据。

使用 execute_update() 方法来执行 DML 语句。

# instance_id = "your-spanner-instance" # database_id = "your-spanner-db-id"  spanner_client = spanner.Client() instance = spanner_client.instance(instance_id) database = instance.database(database_id)  def transfer_budget(transaction):     # Transfer marketing budget from one album to another. Performed in a     # single transaction to ensure that the transfer is atomic.     second_album_result = transaction.execute_sql(         "SELECT MarketingBudget from Albums " "WHERE SingerId = 2 and AlbumId = 2"     )     second_album_row = list(second_album_result)[0]     second_album_budget = second_album_row[0]      transfer_amount = 200000      # Transaction will only be committed if this condition still holds at     # the time of commit. Otherwise it will be aborted and the callable     # will be rerun by the client library     if second_album_budget >= transfer_amount:         first_album_result = transaction.execute_sql(             "SELECT MarketingBudget from Albums "             "WHERE SingerId = 1 and AlbumId = 1"         )         first_album_row = list(first_album_result)[0]         first_album_budget = first_album_row[0]          second_album_budget -= transfer_amount         first_album_budget += transfer_amount          # Update first album         transaction.execute_update(             "UPDATE Albums "             "SET MarketingBudget = @AlbumBudget "             "WHERE SingerId = 1 and AlbumId = 1",             params={"AlbumBudget": first_album_budget},             param_types={"AlbumBudget": spanner.param_types.INT64},         )          # Update second album         transaction.execute_update(             "UPDATE Albums "             "SET MarketingBudget = @AlbumBudget "             "WHERE SingerId = 2 and AlbumId = 2",             params={"AlbumBudget": second_album_budget},             param_types={"AlbumBudget": spanner.param_types.INT64},         )          print(             "Transferred {} from Album2's budget to Album1's".format(                 transfer_amount             )         )  database.run_in_transaction(transfer_budget)

使用 write_with_dml_transaction 参数运行示例。

python snippets.py test-instance --database-id example-db write_with_dml_transaction 

您应该会看到:

Transferred 200000 from Album2's budget to Album1's 

使用二级索引

假设您想要提取 Albums 表中 AlbumTitle 值在特定范围内的所有行。您可以使用 SQL 语句或读取调用读取 AlbumTitle 列中的所有值,然后舍弃不符合条件的行。不过,执行全表扫描费用高昂,特别是对内含大量行的表来说更是如此。相反,如果对表创建二级索引,按非主键列进行搜索,则可以提高行检索速度。

向现有表添加二级索引需要更新架构。与其他架构更新一样,Spanner 支持在数据库继续处理流量的同时添加索引。Spanner 会使用您的现有数据自动回填索引。回填可能需要几分钟时间才能完成,但在此过程中,您无需使数据库离线,也无需避免写入已编入索引的表。如需了解详情,请参阅添加二级索引

添加二级索引后,Spanner 会自动使用该索引进行 SQL 查询,使用该索引后,查询运行速度可能会提高。如果使用读取接口,则必须指定要使用的索引。

添加二级索引

您可以使用 gcloud CLI 在命令行中添加索引,也可以使用 Python 版 Spanner 客户端库以编程方式添加索引。

在命令行中

使用以下 CREATE INDEX 命令向数据库添加索引:

gcloud spanner databases ddl update example-db --instance=test-instance \     --ddl='CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)' 

您应该会看到:

Schema updating...done. 

使用 Python 版 Spanner 客户端库

使用 Database 类的 update_ddl() 方法来添加索引:

def add_index(instance_id, database_id):     """Adds a simple index to the example database."""      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.UpdateDatabaseDdlRequest(         database=database_admin_api.database_path(             spanner_client.project, instance_id, database_id         ),         statements=["CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)"],     )      operation = database_admin_api.update_database_ddl(request)      print("Waiting for operation to complete...")     operation.result(OPERATION_TIMEOUT_SECONDS)      print("Added the AlbumsByAlbumTitle index.")  

使用 add_index 参数运行示例。

python snippets.py test-instance --database-id example-db add_index 

添加索引可能需要几分钟时间。添加索引后,您应该会看到:

Added the AlbumsByAlbumTitle index. 

使用索引进行读取

对于 SQL 查询,Spanner 会自动使用适当的索引。在读取接口中,您必须在请求中指定索引。

如需在读取接口中使用索引,请向 Snapshot 对象的 read() 方法提供 Index 参数。如需获取 Snapshot 对象,请在 with 语句中调用 Database 类的 snapshot() 方法。

def read_data_with_index(instance_id, database_id):     """Reads sample data from the database using an index.      The index must exist before running this sample. You can add the index     by running the `add_index` sample or by running this DDL statement against     your database:          CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle)      """     spanner_client = spanner.Client()     instance = spanner_client.instance(instance_id)     database = instance.database(database_id)      with database.snapshot() as snapshot:         keyset = spanner.KeySet(all_=True)         results = snapshot.read(             table="Albums",             columns=("AlbumId", "AlbumTitle"),             keyset=keyset,             index="AlbumsByAlbumTitle",         )          for row in results:             print("AlbumId: {}, AlbumTitle: {}".format(*row))  

使用 read_data_with_index 参数运行示例。

python snippets.py test-instance --database-id example-db read_data_with_index 

您应该会看到:

AlbumId: 2, AlbumTitle: Forever Hold Your Peace AlbumId: 2, AlbumTitle: Go, Go, Go AlbumId: 1, AlbumTitle: Green AlbumId: 3, AlbumTitle: Terrified AlbumId: 1, AlbumTitle: Total Junk 

添加索引以进行纯索引读取

您可能已经注意到,上面的读取示例不包括读取 MarketingBudget 列。这是因为,Spanner 的读取接口不支持将索引与数据表联接来查找未存储在索引中的值。

请创建 AlbumsByAlbumTitle 的备用定义,用于将 MarketingBudget 的副本存储到索引中。

在命令行中

GoogleSQL

gcloud spanner databases ddl update example-db --instance=test-instance \     --ddl='CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) STORING (MarketingBudget) 

PostgreSQL

gcloud spanner databases ddl update example-db --instance=test-instance \     --ddl='CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) INCLUDE (MarketingBudget) 

添加索引可能需要几分钟时间。添加索引后,您应该会看到:

Schema updating...done. 

使用 Python 版 Spanner 客户端库

使用 Database 类的 update_ddl() 方法来添加带 STORING 子句的索引。

def add_storing_index(instance_id, database_id):     """Adds an storing index to the example database."""      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.UpdateDatabaseDdlRequest(         database=database_admin_api.database_path(             spanner_client.project, instance_id, database_id         ),         statements=[             "CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle)"             "STORING (MarketingBudget)"         ],     )      operation = database_admin_api.update_database_ddl(request)      print("Waiting for operation to complete...")     operation.result(OPERATION_TIMEOUT_SECONDS)      print("Added the AlbumsByAlbumTitle2 index.")  

使用 add_storing_index 参数运行示例。

python snippets.py test-instance --database-id example-db add_storing_index 

您应该会看到:

Added the AlbumsByAlbumTitle2 index. 

现在,当您执行读取操作时便可从 AlbumsByAlbumTitle2 索引中提取所有 AlbumIdAlbumTitleMarketingBudget 列:

def read_data_with_storing_index(instance_id, database_id):     """Reads sample data from the database using an index with a storing     clause.      The index must exist before running this sample. You can add the index     by running the `add_scoring_index` sample or by running this DDL statement     against your database:          CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle)         STORING (MarketingBudget)      """     spanner_client = spanner.Client()     instance = spanner_client.instance(instance_id)     database = instance.database(database_id)      with database.snapshot() as snapshot:         keyset = spanner.KeySet(all_=True)         results = snapshot.read(             table="Albums",             columns=("AlbumId", "AlbumTitle", "MarketingBudget"),             keyset=keyset,             index="AlbumsByAlbumTitle2",         )          for row in results:             print("AlbumId: {}, AlbumTitle: {}, " "MarketingBudget: {}".format(*row))  

使用 read_data_with_storing_index 参数运行示例。

python snippets.py test-instance --database-id example-db read_data_with_storing_index 

您看到的输出结果应该类似于以下内容:

AlbumId: 2, AlbumTitle: Forever Hold Your Peace, MarketingBudget: 300000 AlbumId: 2, AlbumTitle: Go, Go, Go, MarketingBudget: None AlbumId: 1, AlbumTitle: Green, MarketingBudget: None AlbumId: 3, AlbumTitle: Terrified, MarketingBudget: None AlbumId: 1, AlbumTitle: Total Junk, MarketingBudget: 300000 

使用只读事务检索数据

假设您要在同一时间戳执行多个读取操作。只读事务会观察事务提交记录的一致前缀,以便应用始终获得一致的数据。 使用 Snapshot 对象执行只读事务。如需获取 Snapshot 对象,请在 with 语句中调用 Database 类的 snapshot() 方法。

下面演示了如何运行查询并在同一只读事务中执行读取操作:

def read_only_transaction(instance_id, database_id):     """Reads data inside of a read-only transaction.      Within the read-only transaction, or "snapshot", the application sees     consistent view of the database at a particular timestamp.     """     spanner_client = spanner.Client()     instance = spanner_client.instance(instance_id)     database = instance.database(database_id)      with database.snapshot(multi_use=True) as snapshot:         # Read using SQL.         results = snapshot.execute_sql(             "SELECT SingerId, AlbumId, AlbumTitle FROM Albums"         )          print("Results from first read:")         for row in results:             print("SingerId: {}, AlbumId: {}, AlbumTitle: {}".format(*row))          # Perform another read using the `read` method. Even if the data         # is updated in-between the reads, the snapshot ensures that both         # return the same data.         keyset = spanner.KeySet(all_=True)         results = snapshot.read(             table="Albums", columns=("SingerId", "AlbumId", "AlbumTitle"), keyset=keyset         )          print("Results from second read:")         for row in results:             print("SingerId: {}, AlbumId: {}, AlbumTitle: {}".format(*row))  

使用 read_only_transaction 参数运行示例。

python snippets.py test-instance --database-id example-db read_only_transaction 

您看到的输出结果应该类似于以下内容:

Results from first read: SingerId: 2, AlbumId: 2, AlbumTitle: Forever Hold Your Peace SingerId: 1, AlbumId: 2, AlbumTitle: Go, Go, Go SingerId: 2, AlbumId: 1, AlbumTitle: Green SingerId: 2, AlbumId: 3, AlbumTitle: Terrified SingerId: 1, AlbumId: 1, AlbumTitle: Total Junk Results from second read: SingerId: 1, AlbumId: 1, AlbumTitle: Total Junk SingerId: 1, AlbumId: 2, AlbumTitle: Go, Go, Go SingerId: 2, AlbumId: 1, AlbumTitle: Green SingerId: 2, AlbumId: 2, AlbumTitle: Forever Hold Your Peace SingerId: 2, AlbumId: 3, AlbumTitle: Terrified 

清理

为避免因本教程中使用的资源导致您的 Google Cloud 账号产生额外费用,请删除数据库和您创建的实例。

删除数据库

如果您删除一个实例,则该实例中的所有数据库都会自动删除。 本步骤演示了如何在不删除实例的情况下删除数据库(您仍需为该实例付费)。

在命令行中

gcloud spanner databases delete example-db --instance=test-instance 

使用 Google Cloud 控制台

  1. 前往 Google Cloud 控制台中的 Spanner 实例页面。

    转到“实例”页面

  2. 点击实例。

  3. 点击您想删除的数据库。

  4. 数据库详细信息页面中,点击删除

  5. 确认您要删除数据库并点击删除

删除实例

删除实例会自动删除在该实例中创建的所有数据库。

在命令行中

gcloud spanner instances delete test-instance 

使用 Google Cloud 控制台

  1. 前往 Google Cloud 控制台中的 Spanner 实例页面。

    转到“实例”页面

  2. 点击您的实例。

  3. 点击删除

  4. 确认您要删除实例并点击删除

后续步骤