分区数据操纵语言(分区 DML)专为以下类型的批量更新和删除而设计:
- 定期清理和垃圾回收。例如,删除旧行或将列设置为
NULL
。 - 使用默认值回填新列。例如,使用
UPDATE
语句将新列当前的NULL
值设置为False
。
分区 DML 不适用于小规模事务处理。如果您想对几行运行语句,请使用带有可识别主键的事务性 DML。如需了解详情,请参阅使用 DML。
如果您需要提交大量盲目写入,但不需要原子事务,则可以使用批量写入来批量修改 Spanner 表。如需了解详情,请参阅使用批量写入修改数据。
您可以从 Spanner 数据库中的统计信息表中深入了解正在进行的分区 DML 查询及其进度。如需了解详情,请参阅有效的分区 DML 统计信息。
DML 和分区 DML
Spanner 支持 DML 语句的两种执行模式:
DML,适用于事务处理。如需了解详情,请参阅使用 DML。
分区 DML,通过在较小范围的单独事务中对键空间进行分区并在分区上运行语句,实现了大规模、数据库范围的操作,同时将对并发事务处理的影响降至最低。如需了解详情,请参阅使用分区 DML。
下表着重说明了两种执行模式之间的一些差异。
DML | 分区 DML |
---|---|
与 WHERE 子句不匹配的行可能会加以锁定。 |
仅锁定与 WHERE 子句匹配的行。 |
适用事务大小限制。 | Spanner 会处理事务限制和每个事务的并发限制。 |
语句不需要具有幂等性。 | DML 语句必须具有幂等性,以确保一致结果。 |
一个事务可以包括多个 DML 和 SQL 语句。 | 一个分区事务只能包含一个 DML 语句。 |
对语句的复杂程度没有限制。 | 语句必须是完全可分区的。 |
您可以在客户端代码中创建读写事务。 | Spanner 创建事务。 |
可分区和幂等性
运行分区 DML 语句时,一个分区中的行无权访问其他分区中的行,且您无法选择 Spanner 创建分区的方式。分区确保了可伸缩性,但这也意味着分区 DML 语句必须是“完全可分区的”。也就是说,分区 DML 语句必须可表示为一组语句的并集,其中每个语句访问表的单一行,并且每个语句不访问其他表。例如,访问多个表或执行自连接的 DML 语句不可分区。如果 DML 语句不可分区,则 Spanner 会返回错误 BadUsage
。
这些 DML 语句是完全可分区的,因为每个语句都可以应用于表中的单一行:
UPDATE Singers SET LastName = NULL WHERE LastName = '';
DELETE FROM Albums WHERE MarketingBudget > 10000;
此 DML 语句不是完全可分区的,因为它访问多个表:
# Not fully partitionable
DELETE FROM Singers WHERE
SingerId NOT IN (SELECT SingerId FROM Concerts);
由于网络级层重试,Spanner 可能会对某些分区多次执行分区 DML 语句。因此,语句可能会对一行多次执行。所以该语句必须具有幂等性才能产生一致的结果。如果对单一行多次执行语句会产生相同的结果,则该语句具有幂等性。
此 DML 语句具有幂等性:
UPDATE Singers SET MarketingBudget = 1000 WHERE true;
此 DML 语句不具有幂等性:
UPDATE Singers SET MarketingBudget = 1.5 * MarketingBudget WHERE true;
行锁定
仅当行是更新或删除的候选对象时,Spanner 才会获取锁定。此行为与 DML 执行不同,后者可能会对与 WHERE
子句不匹配的行进行读取锁定。
执行和事务
DML 语句是否已分区取决于您选择执行的客户端库方法。每个客户端库会为 DML 执行和分区 DML 执行提供单独的方法。
在调用客户端库方法时,一次只能执行一个分区 DML 语句。
Spanner 不会在整个表中以原子方式应用分区 DML 语句。但是,Spanner 会在每个分区上以原子方式应用分区 DML 语句。
分区 DML 不支持提交或回滚。Spanner 立即执行并应用 DML 语句。
- 如果您取消操作,则 Spanner 会取消正在执行的分区,并且不会启动其余分区。Spanner 不会回滚已执行的任何分区。
- 如果语句的执行导致错误,则会在所有分区上停止执行,Spanner 将针对整个操作返回该错误。错误示例包括违反数据类型限制、违反
UNIQUE INDEX
和违反ON DELETE NO ACTION
。根据执行失败的时间点,语句可能已成功针对某些分区运行,并且可能永远不会针对其他分区运行。
如果分区 DML 语句成功,则 Spanner 对键范围的每个分区运行该语句至少一次。
已修改行的计数
分区 DML 语句返回已修改行数的下限。它可能不是已修改行数的精确计数,因为无法保证 Spanner 计算了所有已修改的行。
事务限制
Spanner 会创建执行分区 DML 语句所需的分区和事务。系统会适用事务限制或每个事务的并发限制,但 Spanner 会尝试将事务保持在限制范围内。
Spanner 允许每个数据库最多 20,000 个并发的分区 DML 语句。
不受支持的功能
Spanner 不支持分区 DML 的某些功能:
- 不支持
INSERT
。 - Google Cloud 控制台:您无法在 Google Cloud 控制台中执行分区 DML 语句。
- 查询计划和性能分析:Google Cloud CLI 和客户端库不支持查询计划和性能分析。
- 从其他表或同一表中的不同行读取的子查询。
对于复杂场景(例如移动表或需要跨表联接的转换),请考虑使用 Dataflow 连接器。
示例
以下代码示例更新 Albums
表的 MarketingBudget
列。
C++
您可以使用 ExecutePartitionedDml()
函数来执行分区 DML 语句。
C#
您可以使用 ExecutePartitionedUpdateAsync()
方法来执行分区 DML 语句。
Go
您可以使用 PartitionedUpdate()
方法来执行分区 DML 语句。
Java
您可以使用 executePartitionedUpdate()
方法来执行分区 DML 语句。
Node.js
您可以使用 runPartitionedUpdate()
方法来执行分区 DML 语句。
PHP
您可以使用 executePartitionedUpdate()
方法来执行分区 DML 语句。
Python
您可以使用 execute_partitioned_dml()
方法来执行分区 DML 语句。
Ruby
您可以使用 execute_partitioned_update()
方法来执行分区 DML 语句。
以下代码示例根据 SingerId
列从 Singers
表中删除行。
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
后续步骤
了解如何使用 DML 来修改数据。
如需了解 DML 和变更之间的差异,请参阅比较 DML 和变更
考虑针对其他数据转换场景使用 Dataflow 连接器。