本页面介绍了如何在上下文之外在 Spanner 中执行读取操作。 读写事务如果您属于以下任一情况 您应改为参阅事务页面:
如果需要写入,则根据一个或多个读取的值,应该将读取作为读写事务的一部分执行。有关 请参阅 读写事务。
如果您正在进行多次读取调用,并且它们需要数据的一致视图,则应该将读取作为只读事务的一部分执行。如需了解详情,请参阅只读事务。
读取类型
Spanner 提供两种类型的读取,让您能在读取数据时确定数据的新鲜程度:
- “强读”是读取当前时间戳处的数据,并保证能够查看读取开始之前已提交的所有数据。Spanner 默认使用强读来处理读取请求。
- “过时读取”是读取过去时间戳处的数据。如果您的应用对延迟比较敏感,但能容忍过时数据,则过时读取可以带来性能优势。
如需选择所需的读取类型,请设置时间戳边界 读取请求中包含的资源选择时间戳时,请遵循以下最佳实践 绑定:
尽可能选择强读。这些是默认时间戳 受 Spanner 读取(包括只读事务)的约束。强读保证能够观察到在操作开始之前提交的所有事务的影响,这与哪个副本接收读取无关。正因为如此,强读使应用代码更简单,应用更可靠。如需详细了解 Spanner 的一致性特性,请参阅 TrueTime 和外部一致性。
如果在某些情况下,延迟导致无法执行强读,则可以使用过时读取(有界限过时或精确过时)来提高不要求读取尽可能新鲜的场合的性能。如描述 在复制页面上,15 秒是 合理过时值,以提高性能。
以数据库角色读取数据
如果您是精细访问权限控制用户,则必须选择数据库角色才能执行 SQL 语句和查询,以及对数据库执行行操作。您的角色选择在整个会话期间保持不变 直到您更改角色为止。
如需了解如何使用数据库角色执行读取操作,请参阅使用精细访问权限控制访问数据库。
单次读取方法
Spanner 支持单次读取方法(即 事务上下文)在数据库中执行以下操作:
- 将读取作为 SQL 查询语句执行或使用 Spanner 的 read API。
- 对表中的单行或多行执行强读。
- 从表中的单行或多行执行过时读取。
- 从二级索引中的单行或多行读取。
如果要将单个读取操作路由到特定副本或区域 多区域实例配置或自定义区域配置中 具有可选只读区域,请参阅定向读取。
以下部分介绍了如何使用 Spanner 客户端库使用读取方法。
执行查询
下面演示了如何对数据库执行 SQL 查询语句。
GoogleSQL
C++
使用 ExecuteQuery()
对数据库执行 SQL 查询语句。
C#
使用 ExecuteReaderAsync()
来查询数据库。
Go
使用 Client.Single().Query
来查询数据库。
Java
使用 ReadContext.executeQuery
来查询数据库。
Node.js
使用 Database.run
来查询数据库。
PHP
使用 Database::execute
来查询数据库。
Python
使用 Database.execute_sql
来查询数据库。
Ruby
使用 Client#execute
来查询数据库。
构造 SQL 语句时,请参阅 SQL 查询语法以及函数和运算符参考资料。
执行强读
下面演示了如何对数据库中的零行或多行执行强读。
GoogleSQL
C++
读取数据的代码与前一个通过执行 SQL 查询来查询 Spanner 的示例相同。
C#
读取数据的代码与上一个查询示例相同 通过执行 SQL 查询访问 Spanner。
Go
使用 Client.Single().Read
从数据库中读取行。
该示例使用 AllKeys
来定义要读取的键或键范围的集合。
Java
使用 ReadContext.read
从数据库中读取行。
该示例使用 KeySet
来定义要读取的键或键范围的集合。
Node.js
使用 Table.read
从数据库中读取行。
该示例使用 keySet
来定义要读取的键或键范围的集合。
PHP
使用 Database::read
从数据库中读取行。
该示例使用 keySet
来定义要读取的键或键范围的集合。
Python
使用 Database.read
从数据库中读取行。
该示例使用 KeySet
来定义要读取的键或键范围的集合。
Ruby
使用 Client#read
从数据库中读取行。
执行过时读取
以下示例代码演示了如何使用精确过时时间戳边界对数据库中的零行或多行执行过时读取。如需了解如何使用有界限过时时间戳边界执行过时读取,请参阅示例代码后面的注释。如需详细了解不同类型的可用时间戳边界,请参阅时间戳边界。
GoogleSQL
C++
将 ExecuteQuery()
与 MakeReadOnlyTransaction()
和 Transaction::ReadOnlyOptions()
配合使用以执行过时读取。
C#
对具有指定 TimestampBound.OfExactStaleness()
值的 connection
使用 BeginReadOnlyTransactionAsync
方法来查询数据库。
Go
使用 Client.ReadOnlyTransaction().WithTimestampBound()
并指定 ExactStaleness
值,以使用精确过时时间戳边界读取数据库中的行。
该示例使用 AllKeys
来定义要读取的键或键范围的集合。
Java
对具有指定 TimestampBound.ofExactStaleness()
的 ReadContext
使用 read
方法,通过精确过时时间戳边界读取数据库中的行。
该示例使用 KeySet
来定义要读取的键或键范围的集合。
Node.js
搭配使用 Table.read
和 exactStaleness
选项,利用精确过时时间戳边界读取数据库中的行。
该示例使用 keySet
来定义要读取的键或键范围的集合。
PHP
利用 Database::read
和指定的 exactStaleness
值,通过精确过时时间戳边界读取数据库中的行。
该示例使用 keySet
来定义要读取的键或键范围的集合。
Python
对具有指定 exact_staleness
的 Database
snapshot
使用 read
方法,通过精确过时时间戳边界读取数据库中的行。
该示例使用 KeySet
来定义要读取的键或键范围的集合。
Ruby
对具有指定 staleness
值(以秒为单位)的快照 Client
使用 read
方法,通过精确过时时间戳边界从数据库读取行。
使用索引执行读取
下面演示了如何使用索引从数据库读取零行或多行:
GoogleSQL
C++
使用 Read()
函数通过索引执行读取。
C#
执行一个显式指定索引的查询,通过索引读取数据:
Go
使用 Client.Single().ReadUsingIndex
,以便通过索引从数据库读取行。
Java
使用 ReadContext.readUsingIndex
,以便通过索引从数据库读取行。
Node.js
使用 Table.read
并在查询中指定索引,以便通过索引从数据库读取行。
PHP
使用 Database::read
并指定索引,以便通过索引从数据库读取行。
Python
使用 Database.read
并指定索引,以便通过索引从数据库读取行。
Ruby
使用 Client#read
并指定索引,以便通过索引从数据库读取行。
并行读取数据
执行涉及大量
可以使用 PartitionQuery
更快地获得结果。该 API 会使用多台机器并行提取分区,从而将查询划分为批次或“分区”。是
请注意,使用 PartitionQuery
API 会导致较长的延迟时间,
只能用于批量操作,例如导出或扫描
数据库。
您可以使用 Spanner 客户端库并行执行任何读取 API 操作。不过,只有在查询必须满足以下条件时,您才能对 SQL 查询进行分区: 可根分区若要将查询分区为根分区,查询计划必须满足以下条件之一:
PartitionQuery
API 以批量模式运行查询。Spanner 可能会选择一种查询执行计划,使查询在批量模式下运行时可分为根分区。因此,PartitionQuery
API 和 Spanner Studio 可能会针对同一查询使用不同的查询执行计划。您可能无法获取查询执行计划
由 Spanner Studio 上的 PartitionQuery
API 使用。
对于此类分区查询,您可以选择启用 Spanner Data Boost。借助 Data Boost,您可以运行大型分析查询,且对预配的 Spanner 实例上的现有工作负载几乎没有影响。C++、Go、Java、Node.js 和 Python 此页面上的代码示例展示了如何启用 Data Boost。
如需详细了解 Data Boost,请参阅 Data Boost 概览。
GoogleSQL
C++
此示例提取 Singers
表的 SQL 查询分区,并按照以下步骤对每个分区执行查询:
- 创建 Spanner 批处理事务。
- 为查询生成分区,以便可以将分区分发给多个工作器。
- 检索每个分区的查询结果。
C#
此示例提取 Singers
表的 SQL 查询分区,并按照以下步骤对每个分区执行查询:
- 创建 Spanner 批处理事务。
- 为查询生成分区,以便可以将分区分发给多个工作器。
- 检索每个分区的查询结果。
Go
此示例提取 Singers
表的 SQL 查询分区,并按照以下步骤对每个分区执行查询:
- 创建 Spanner 客户端和事务。
- 为查询生成分区,以便可以将分区分发给多个工作器。
- 检索每个分区的查询结果。
Java
此示例提取 Singers
表的 SQL 查询分区,并按照以下步骤对每个分区执行查询:
- 创建 Spanner 批处理客户端和事务。
- 为查询生成分区,以便可以将分区分发给多个工作器。
- 检索每个分区的查询结果。
Node.js
此示例提取 Singers
表的 SQL 查询分区,并按照以下步骤对每个分区执行查询:
- 创建一个 Spanner 客户端和一个批处理。
- 为查询生成分区,以便可以将分区分发给多个工作器。
- 检索每个分区的查询结果。
PHP
此示例提取 Singers
表的 SQL 查询分区,并按照以下步骤对每个分区执行查询:
- 创建一个 Spanner 客户端和一个批处理。
- 为查询生成分区,以便可以将分区分发给多个工作器。
- 检索每个分区的查询结果。
Python
此示例提取 Singers
表的 SQL 查询分区,并按照以下步骤对每个分区执行查询:
- 创建一个 Spanner 客户端和一个批处理事务。
- 为查询生成分区,以便可以将分区分发给多个工作器。
- 检索每个分区的查询结果。
Ruby
此示例提取 Singers
表的 SQL 查询分区,并按照以下步骤对每个分区执行查询:
- 创建 Spanner 批处理客户端。
- 为查询创建分区,以便可以将分区分发给多个工作器。
- 检索每个分区的查询结果。