Pipelined DML
本文档介绍了与 Pipelined DML 相关的使用场景、方法、限制以及常见问题。
概述
Pipelined DML 是在 TiDB v8.0.0 中引入的一个实验性功能,旨在提升大规模数据写入操作的性能。当启用此功能时,TiDB 在执行 DML 操作时会将数据直接流式传输到存储层,而不是全部缓存在内存中。这种类似流水线的方式在读取数据(输入)和写入存储层(输出)时同时进行,有效解决了以下常见的在大规模 DML 操作中遇到的问题:
- 内存限制:传统的 DML 操作在处理大数据集时可能会遇到内存溢出(OOM)错误。
- 性能瓶颈:大事务通常效率较低,容易引起工作负载波动。
启用 pipelined DML 后,你可以实现:
- 执行大规模数据操作而不受 TiDB 内存限制的约束。
- 保持工作负载的平稳,降低操作延迟。
- 使事务的内存使用保持可控,通常在 1 GiB 以内。
建议在以下场景中启用 Pipelined DML:
- 处理涉及数百万行或更多的数据写入。
- 在 DML 操作中遇到内存不足的错误。
- 在大规模数据操作中出现明显的工作负载波动。
注意,虽然 Pipelined DML 在事务处理过程中显著降低了内存使用,但你仍需配置一个合理的内存阈值(建议至少 2 GiB),以确保其他组件(如执行器)在大规模数据操作期间正常运行。
限制
目前,Pipelined DML 存在以下限制:
- Pipelined DML 目前与 TiCDC、TiFlash 或 BR 不兼容。避免在与这些组件相关的表上使用 Pipelined DML,否则可能导致这些组件出现阻塞或 OOM 等问题。
- Pipelined DML 不适用于存在写冲突的场景,因为可能导致性能大幅下降或操作失败需要回滚。
- 在进行 Pipelined DML 操作时,确保启用了元数据锁。
- 在启用 Pipelined DML 执行 DML 语句时,TiDB 会检查以下条件。如果任何条件不满足,TiDB 会回退到标准 DML 执行,并生成警告:
- 仅支持 autocommit 语句。
- 仅支持
INSERT
、UPDATE
、REPLACE
和DELETE
语句。 - 目标表不能包含 临时表 或 缓存表。
- 当启用 外键约束(
foreign_key_checks = ON
)时,目标表不能包含外键关系。
- 执行
INSERT IGNORE ... ON DUPLICATE KEY UPDATE
语句时,冲突的更新可能导致Duplicate entry
错误。
使用方法
本节介绍如何启用 Pipelined DML 以及如何验证其是否生效。
启用 Pipelined DML
你可以通过以下方法之一启用 Pipelined DML:
为当前会话启用 Pipelined DML,将
tidb_dml_type
变量设置为"bulk"
:SET tidb_dml_type = "bulk";在特定语句中启用 Pipelined DML,添加
SET_VAR
提示。数据归档示例:
INSERT /*+ SET_VAR(tidb_dml_type='bulk') */ INTO target_table SELECT * FROM source_table;批量数据更新示例:
UPDATE /*+ SET_VAR(tidb_dml_type='bulk') */ products SET price = price * 1.1 WHERE category = 'electronics';批量删除示例:
DELETE /*+ SET_VAR(tidb_dml_type='bulk') */ FROM logs WHERE log_time < '2023-01-01';
验证 Pipelined DML
在执行完 DML 语句后,可以通过检查 tidb_last_txn_info
变量,验证是否启用了 Pipelined DML:
SELECT @@tidb_last_txn_info;
如果输出中的 pipelined
字段为 true
,表示成功使用 Pipelined DML。
最佳实践
- 略微增加
tidb_mem_quota_query
的值,以确保执行器等组件的内存使用不会超过限制。建议至少设置为 2 GiB。对于内存充足的环境,可以进一步提高此值。 - 在向新表插入数据的场景中,Pipelined DML 的性能可能会受到热点的影响。为了获得最佳性能,建议提前解决热点问题。更多信息请参见 Troubleshoot Hotspot Issues。
相关配置
tidb_dml_type
系统变量控制是否在会话层启用 Pipelined DML。- 当
tidb_dml_type
设置为"bulk"
时,pessimistic-auto-commit
配置项表现为被设置为false
。 - 使用 Pipelined DML 执行的事务不受 TiDB 配置项
txn-total-size-limit
指定的大小限制。 - 对于使用 Pipelined DML 执行的大事务,事务持续时间可能会增加。在这种情况下,事务锁的最大 TTL 为
max-txn-ttl
和 24 小时中的较大值。 - 如果事务的执行时间超过
tidb_gc_max_wait_time
设置的值,垃圾回收(GC)可能会强制回滚事务,导致事务失败。
监控 Pipelined DML
你可以通过以下方法监控 Pipelined DML 的执行情况:
- 查看
tidb_last_txn_info
系统变量,获取当前会话中最后一次事务的相关信息,包括是否使用了 Pipelined DML。 - 在 TiDB 日志中查找包含
"[pipelined dml]"
的行,以了解 Pipelined DML 的执行过程和进展,包括当前阶段和写入的数据量。 - 查看
expensive query
日志中的affected rows
字段,以跟踪长时间运行语句的进展。 - 查询
INFORMATION_SCHEMA.PROCESSLIST
表,查看事务执行进度。Pipelined DML 通常用于大事务,可以通过此表监控其执行情况。
常见问题解答
为什么我的查询没有使用 Pipelined DML 执行?
当 TiDB 拒绝使用 Pipelined DML 执行语句时,会生成相应的警告信息。你可以执行 SHOW WARNINGS;
来查看警告内容并确认原因。
常见原因:
Pipelined DML 会影响事务的隔离级别吗?
不会。Pipelined DML 只会改变事务中的数据写入机制,不会影响 TiDB 事务的隔离保证。
为什么启用 Pipelined DML 后仍然遇到内存溢出(OOM)错误?
即使启用了 Pipelined DML,你仍可能遇到因内存限制导致的查询终止:
The query has been canceled due to exceeding the memory limit allowed for a single SQL query. Please try to narrow the query scope or increase the tidb_mem_quota_query limit, and then try again.
此错误发生的原因是 Pipelined DML 仅控制事务执行期间数据的内存使用。而在语句执行过程中,其他组件(如执行器)也会占用内存。如果总的内存需求超过了 TiDB 的内存限制,就可能出现 OOM 错误。
在大多数情况下,你可以通过将系统变量 tidb_mem_quota_query
设置为更高的值来解决此问题。建议至少设置为 2 GiB。对于包含复杂操作符或涉及大数据集的 SQL 语句,可能需要进一步增加此值。