本页面介绍了如何在只读和读写事务上下文之外在 Spanner 中执行读取操作。如果满足以下任一条件,您应改为参阅事务页面:
如果需要写入,则根据一个或多个读取的值,应该将读取作为读写事务的一部分执行。如需了解详情,请参阅读写事务。
如果您正在进行多次读取调用,并且它们需要数据的一致视图,则应该将读取作为只读事务的一部分执行。如需了解详情,请参阅只读事务。
读取类型
Spanner 提供两种类型的读取,让您可在读取数据时确定数据的新近度:
- “强读”是读取当前时间戳处的数据,并保证能够查看读取开始之前已提交的所有数据。Spanner 默认使用强读来处理读取请求。
- “过时读取”是读取过去时间戳处的数据。如果您的应用对延迟比较敏感,但能容忍过时数据,则过时读取可以带来性能优势。
如需选择所需的读取类型,请在读取请求上设置时间戳边界。选择时间戳边界时,请遵循以下最佳实践:
尽可能选择强读。这些是 Spanner 读取(包括只读事务)的默认时间戳边界。强读保证能够观察到在操作开始之前提交的所有事务的影响,这与哪个副本接收读取无关。正因为如此,强读使应用代码更简单,应用更可靠。如需详细了解 Spanner 的一致性属性,请参阅 TrueTime 和外部一致性。
如果在某些情况下,延迟导致强读不可行,则可以使用过时读取(有界限过时或精确过时),在不需要读取尽可能近的场景中提高性能。如复制页面中所述,15 秒是一个合理的过时值,有助于提高性能。
以数据库角色读取数据
如果您是精细访问权限控制用户,则必须选择数据库角色才能执行 SQL 语句和查询,以及对数据库执行行操作。您的角色选择在整个会话期间保持不变,直到您更改角色。
如需了解如何使用数据库角色执行读取操作,请参阅通过精细的访问权限控制访问数据库。
单次读取方法
Spanner 支持对数据库使用单次读取方法(即在事务上下文之外进行读取),以便:
- 以 SQL 查询语句形式或使用 Spanner 的读取 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
并指定索引,以便通过索引从数据库读取行。
并行读取数据
在执行涉及 Spanner 中的大量数据的批量读取或查询操作时,您可以使用 PartitionQuery
API 更快地获得结果。该 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 批处理客户端。
- 为查询创建分区,以便可以将分区分发给多个工作器。
- 检索每个分区的查询结果。