From a31d70836dcc12f54d9b30ecdd1798b1067c740c Mon Sep 17 00:00:00 2001 From: ekexium Date: Wed, 8 Jan 2025 16:32:19 +0800 Subject: [PATCH] doc: batch processing overview and pipelined dml (#19021) --- TOC.md | 2 + batch-processing.md | 97 +++++++++++++++++++++++++++++ pipelined-dml.md | 148 ++++++++++++++++++++++++++++++++++++++++++++ system-variables.md | 13 +--- 4 files changed, 248 insertions(+), 12 deletions(-) create mode 100644 batch-processing.md create mode 100644 pipelined-dml.md diff --git a/TOC.md b/TOC.md index 5eebe00e5b90..407800ae3379 100644 --- a/TOC.md +++ b/TOC.md @@ -391,6 +391,7 @@ - [Load Base Split 使用文档](/configure-load-base-split.md) - [Store Limit 使用文档](/configure-store-limit.md) - [DDL 执行原理及最佳实践](/ddl-introduction.md) + - [数据批量处理](/batch-processing.md) - PD 微服务使用文档 - [PD 微服务概览](/pd-microservices.md) - [使用 TiUP 扩容缩容 PD 微服务节点](/scale-microservices-using-tiup.md) @@ -941,6 +942,7 @@ - [乐观事务](/optimistic-transaction.md) - [悲观事务](/pessimistic-transaction.md) - [非事务 DML 语句](/non-transactional-dml.md) + - [Pipelined DML](/pipelined-dml.md) - [视图](/views.md) - [分区表](/partitioned-table.md) - [临时表](/temporary-tables.md) diff --git a/batch-processing.md b/batch-processing.md new file mode 100644 index 000000000000..96623010cbdb --- /dev/null +++ b/batch-processing.md @@ -0,0 +1,97 @@ +--- +title: 数据批量处理 +summary: 介绍了 TiDB 为数据批量处理场景提供的功能,包括 Pipelined DML、非事务性 DML、IMPORT INTO 语句以及已被废弃的 batch-dml。 +--- + +# 数据批量处理 + +批量数据处理是实际业务中常见且重要的操作,它涉及到对大量数据进行高效操作,如数据迁移、批量导入、归档操作或大规模更新等。 + +为了提升批量处理性能,TiDB 随着版本的演进提供了多种数据批量处理功能: + +- 数据导入 + - `IMPORT INTO` 语句(从 TiDB v7.2.0 开始引入,在 v7.5.0 成为正式功能) +- 数据增删改 + - Pipelined DML(从 TiDB v8.0.0 开始引入,实验特性) + - 非事务性 DML(从 TiDB v6.1.0 开始引入) + - 已废弃的 batch-dml 功能 + +本文分别介绍这些功能的主要优势、限制和使用场景,帮助你根据实际需求选择合适的方案,从而更高效地完成批量数据处理任务。 + +## 数据导入 + +`IMPORT INTO` 语句专为数据导入设计,使你无需单独部署 [TiDB Lightning](/tidb-lightning/tidb-lightning-overview.md),即可将 CSV、SQL 或 PARQUET 等格式的数据快速导入到 TiDB 的一张空表中。 + +主要优势: + +- 导入速度非常快。 +- 比 TiDB Lightning 更易用。 + +主要限制: + +- 不满足事务 [ACID](/glossary.md#acid) 性质。 +- 使用限制较多。 + +适用场景: + +- 数据导入场景,例如数据迁移、数据恢复等。建议在合适的场景下,使用 IMPORT INTO 代替 TiDB Lightning。 + +更多信息,请参考 [`IMPORT INTO`](/sql-statements/sql-statement-import-into.md)。 + +## 数据增删改 + +### Pipelined DML + +Pipelined DML 是从 TiDB v8.0.0 开始引入的实验特性。在 v8.5.0 中,TiDB 对该功能进行了完善,其性能得到大幅提升。 + +主要优势: + +- 在事务执行过程中,通过将数据持续写入存储层,而不是全部缓存在内存中,使得事务大小不再受到 TiDB 内存限制,支持处理超大规模数据。 +- 性能比标准 DML 更好。 +- 通过系统变量启用,无需修改 SQL 语句。 + +主要限制: + +- 只适用于[自动提交](/transaction-overview.md#自动提交)的 `INSERT`、`REPLACE`、`UPDATE`、`DELETE` 语句。 + +适用场景: + +- 通用的批量数据处理场景,例如大量数据的插入、更新、删除等。 + +更多信息,请参考 [Pipelined DML](/pipelined-dml.md)。 + +### 非事务 DML 语句 + +非事务 DML 语句是从 TiDB v6.1.0 开始引入的功能。在 v6.1.0 中,该功能仅支持 `DELETE` 语句。从 v6.5.0 起,该功能新增支持 `INSERT`、`REPLACE`、`UPDATE` 语句。 + +主要优势: + +- 通过将一条 SQL 语句拆为多条语句执行,使得每个语句的事务更小,绕开内存限制。 +- 处理速度比标准 DML 稍快或相当。 + +主要限制: + +- 只适用于[自动提交](/transaction-overview.md#自动提交)的语句。 +- 需要修改 SQL 语句。 +- 对 SQL 语句本身限制较多,不符合条件的语句可能需要改写。 +- 因为 SQL 语句被拆分执行,不具有完整的事务 ACID 性质,在失败时语句可能部分完成。 + +适用场景: + +- 大量数据的插入、更新、删除等场景。由于限制较多,建议在 Pipelined DML 不适用的场景下考虑使用。 + +更多信息,请参考[非事务 DML 语句](/non-transactional-dml.md)。 + +### 已被废弃的 batch-dml + +TiDB 在 v4.0 之前提供了 batch-dml 功能,用于批量数据处理。该功能已被废弃,不再推荐使用。batch-dml 功能由以下这些系统变量控制: + +- `tidb_batch_insert` +- `tidb_batch_delete` +- `tidb_batch_commit` +- `tidb_enable_batch_dml` +- `tidb_dml_batch_size` + +因为该功能可能引起数据索引不一致,导致数据损坏或丢失,以上变量已被废弃,并计划将在未来的版本中逐渐移除。 + +不建议在任何场景下使用已被废弃的 batch-dml 功能。建议选择上面描述的其它方案。 \ No newline at end of file diff --git a/pipelined-dml.md b/pipelined-dml.md new file mode 100644 index 000000000000..dd2e8fd26839 --- /dev/null +++ b/pipelined-dml.md @@ -0,0 +1,148 @@ +--- +title: Pipelined DML +summary: 介绍 Pipelined DML 的使用场景、使用方法、使用限制和使用该功能的常见问题。Pipelined DML 增强了 TiDB 批量处理的能力,使得事务大小不再受到 TiDB 内存限制。 +--- + +# Pipelined DML + +> **警告:** +> +> 该功能目前为实验特性,不建议在生产环境中使用。该功能可能会在未事先通知的情况下发生变化或删除。语法和实现可能会在 GA 前发生变化。如果发现 bug,请在 GitHub 上提 [issue](https://github.com/pingcap/tidb/issues) 反馈。 + +本文介绍 Pipelined DML 的使用场景、使用方法、使用限制和使用该功能的常见问题。 + +## 功能概述 + +Pipelined DML 是 TiDB 从 v8.0.0 开始引入的实验特性,用于优化大规模数据写入场景的性能。启用 Pipelined DML 后,当执行 DML 操作时,TiDB 会将相应的数据持续写入存储层,而不是全部缓存在内存中。这种方式就像流水线 (Pipeline) 一样,数据一边被读取(输入),一边被写入到存储层(输出),从而解决了大规模 DML 操作的以下常见问题: + +- 内存限制:传统 DML 在处理大量数据时容易导致 OOM +- 性能瓶颈:大事务执行效率低,容易引起系统负载波动 + +启用此功能后,你可以: + +- 执行不受 TiDB 内存限制的大规模数据操作 +- 获得更平稳的系统负载和更低的操作延迟 +- 将事务内存使用控制在可预测范围内(在 1 GiB 以内) + +在以下场景中,建议考虑启用 Pipelined DML: + +- 需要处理数百万行或更多数据的写入 +- 执行 DML 操作时遇到内存不足错误 +- 大规模数据操作导致系统负载波动明显 + +需要注意的是,虽然 Pipelined DML 能显著降低事务处理的内存需求,但执行大规模数据操作时,仍需要[设置合理的内存阈值](/system-variables.md#tidb_mem_quota_query)(建议至少 2 GiB),以确保除事务以外其他模块(如执行器)的正常运行。 + +## 使用限制 + +目前,Pipelined DML 存在以下使用限制: + +- 与 TiCDC、TiFlash 或 BR 尚不兼容,请勿在与这些组件有关的表上使用 Pipelined DML。强行使用可能会引发阻塞以及这些组件的 OOM 等问题。 +- 不适用于存在写入冲突的场景。在这种场景下,Pipelined DML 性能可能大幅下降,或失败回滚。 +- 在使用 Pipelined DML 执行 DML 语句的过程中,需要确保[元数据锁](/metadata-lock.md)保持开启。 +- 启用 Pipelined DML 后,TiDB 在执行 DML 语句时会自动检测以下条件是否全部符合。如果其中任一条件不符合,TiDB 会拒绝使用 Pipelined DML 执行该语句,自动回退到普通 DML 执行,并生成对应的 warning 信息: + - 仅支持[自动提交](/transaction-overview.md#自动提交)的语句。 + - 仅支持 `INSERT`、`UPDATE`、`REPLACE` 和 `DELETE` 语句。 + - 操作的表不包含[临时表](/temporary-tables.md)或[缓存表](/cached-tables.md)。 + - 当[外键约束](/foreign-key.md)检查开启 (`foreign_key_checks = ON`) 时,操作的表不包含外键关系。 +- 当使用 Pipelined DML 执行 `INSERT IGNORE ... ON DUPLICATE KEY UPDATE` 语句时,如果更新操作发生冲突,可能会返回 `Duplicate entry` 错误。 + +## 使用方法 + +本小节介绍如何启用 Pipelined DML 并验证其是否生效。 + +### 启用 Pipelined DML + +根据需要,你可以选择以下方式之一启用 Pipelined DML: + +- 如需在会话级别启用 Pipelined DML,请将 [`tidb_dml_type`](/system-variables.md#tidb_dml_type-从-v800-版本开始引入) 变量设置为 `"bulk"`: + + ```sql + SET tidb_dml_type = "bulk"; + ``` + +- 如需为某一条 DML 语句启用 Pipelined DML,请在该语句中添加 [`SET_VAR`](/optimizer-hints.md#set_varvar_namevar_value) hint。 + + - 数据归档示例: + + ```sql + INSERT /*+ SET_VAR(tidb_dml_type='bulk') */ INTO target_table SELECT * FROM source_table; + ``` + + - 批量数据更新示例: + + ```sql + UPDATE /*+ SET_VAR(tidb_dml_type='bulk') */ products + SET price = price * 1.1 + WHERE category = 'electronics'; + ``` + + - 批量删除示例: + + ```sql + DELETE /*+ SET_VAR(tidb_dml_type='bulk') */ FROM logs WHERE log_time < '2023-01-01'; + ``` + +### 验证是否生效 + +执行 DML 语句后,可以查看 [`tidb_last_txn_info`](/system-variables.md#tidb_last_txn_info-从-v409-版本开始引入) 变量来确认该语句的执行是否使用了 Pipelined DML: + +```sql +SELECT @@tidb_last_txn_info; +``` + +如果返回结果中 `pipelined` 字段为 `true`,则表示成功使用了 Pipelined DML。 + +## 最佳实践 + +- 将 [`tidb_mem_quota_query`](/system-variables.md#tidb_mem_quota_query) 略微调大,以确保执行器等部分的内存使用不会超过限制。建议至少设置为 2 GiB。对于 TiDB 内存充足的情况,可以适当调大。 +- 在向新表插入数据的场景,Pipelined DML 性能易受到热点影响。为实现最佳性能,建议尽可能先打散热点。可以参考 [TiDB 热点问题处理](/troubleshoot-hot-spot-issues.md)。 + +## 相关配置 + +- 系统变量 [`tidb_dml_type`](/system-variables.md#tidb_dml_type-从-v800-版本开始引入) 用于控制是否在会话级别启用 Pipelined DML。 +- 当 [`tidb_dml_type`](/system-variables.md#tidb_dml_type-从-v800-版本开始引入) 设置为 `"bulk"` 时,配置项 [`pessimistic-auto-commit`](/tidb-configuration-file.md#pessimistic-auto-commit) 的效果等同于设置为 `false`。 +- 以 Pipelined DML 方式执行事务时,事务的大小不受 TiDB 配置项 [`txn-total-size-limit`](/tidb-configuration-file.md#txn-total-size-limit) 的限制。 +- 以 Pipelined DML 方式执行超大事务时,事务耗时可能较长。对于这种模式的事务,其事务锁的最大 TTL 为 [`max-txn-ttl`](/tidb-configuration-file.md#max-txn-ttl) 与 24 小时中的较大值。 +- 当事务执行时间超过 [`tidb_gc_max_wait_time`](/system-variables.md#tidb_gc_max_wait_time-从-v610-版本开始引入) 设定值后,GC 可能会强制回滚事务,导致事务失败。 + +## 观测 Pipelined DML + +你可以通过以下方式观测 Pipelined DML 的执行过程: + +- 查看系统变量 [`tidb_last_txn_info`](/system-variables.md#tidb_last_txn_info-从-v409-版本开始引入),获取当前会话上一个事务的执行信息,包括是否使用了 Pipelined DML。 +- 查看 TiDB 日志中包含 `"[pipelined dml]"` 字样的行,了解 Pipelined DML 的执行过程和进度,包括当前阶段、已经写入的数据量等。 +- 查看 TiDB 日志中的 [`expensive query` 日志](/identify-expensive-queries.md#expensive-query-日志示例)的 `affected rows` 字段,获取耗时较长语句的当前进度。 +- 查看 [`INFORMATION_SCHEMA.PROCESSLIST`](/information-schema/information-schema-processlist.md) 表,了解事务的执行进度。Pipelined DML 通常用于大事务,执行耗时较长,可以通过该表查看事务的执行进度。 + +## 常见问题 + +### 为什么我的查询没有使用 Pipelined DML? + +当 TiDB 拒绝以 Pipelined DML 模式执行语句时,会生成对应的警告信息,可以通过检查警告信息 (`SHOW WARNINGS;`) 确定原因。 + +常见的原因: + +- DML 语句不是自动提交的 +- 使用了不支持的表类型,例如[临时表](/temporary-tables.md)或[缓存表](/cached-tables.md) +- 涉及外键且外键检查开启 + +### Pipelined DML 会影响事务的隔离级别吗? + +不会。Pipelined DML 仅改变了事务写入的实现机制,不影响 TiDB 的事务隔离保证。 + +### 为什么使用了 Pipelined DML 还是会出现内存不足? + +即使开启了 Pipelined DML,仍然有可能碰到内存 quota 不足导致语句被 kill 的情况: + +``` +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 的内存限制,仍然可能会出现内存不足的错误。 + +通常情况下,将系统变量 [`tidb_mem_quota_query`](/system-variables.md#tidb_mem_quota_query) 设置为更大的值可以解决该问题。推荐设置为 2 GiB。对于算子复杂或涉及数据量大的 SQL 语句,可能需要将该变量设置为更大的值。 + +## 探索更多 + +- [批量处理概览](/batch-processing.md) +- [TiDB 内存控制](/configure-memory-usage.md) \ No newline at end of file diff --git a/system-variables.md b/system-variables.md index 5eb7b555c69e..280ec60da50c 100644 --- a/system-variables.md +++ b/system-variables.md @@ -1632,18 +1632,7 @@ mysql> SELECT job_info FROM mysql.analyze_jobs ORDER BY end_time DESC LIMIT 1; - 可选值:`"standard"`、`"bulk"` - 该变量用来设置 DML 语句的执行方式。 - `"standard"` 表示使用标准的 DML 执行方式,TiDB 事务在提交前缓存在内存中。适用于处理高并发且可能存在冲突的事务场景,为默认推荐使用的执行方式。 - - `"bulk"` 表示使用批量 DML 执行方式,适合于处理因大量数据写入导致 TiDB 内存使用过多的情况。 - - 在 TiDB 事务执行过程中,数据不是完全缓存在 TiDB 内存中,而是持续写入 TiKV,以减少内存的占用,同时平滑写入压力。 - - 只有 `INSERT`、`UPDATE`、`REPLACE` 和 `DELETE` 语句受 `"bulk"` 方式的影响。由于 `"bulk"` 模式流水线执行的方式,其中 `INSERT IGNORE ... ON DUPLICATE UPDATE ...` 的用法可能会在更新造成冲突时报出 `Duplicate entry` 的错误;而在 `"standard"` 模式下,由于设置了 `IGNORE` 关键字,该错误会被忽略,不会返回给用户。 - - `"bulk"` 方式仅适用于大批量**无冲突数据写入**的场景,不能高效处理写入冲突的场景,写写冲突可能会导致大批量事务提交失败并被回滚。 - - `"bulk"` 方式只对自动提交 (auto-commit) 的语句生效。当设置为 `"bulk"` 时,[`pessimistic-auto-commit`](/tidb-configuration-file.md#pessimistic-auto-commit) 配置项的效果等同于设置为 `false`。 - - 使用 `"bulk"` 方式执行语句时,需要确保在语句执行过程中保持[元数据锁](/metadata-lock.md)处于开启状态。 - - `"bulk"` 方式不可以在[临时表](/temporary-tables.md)、[缓存表](/cached-tables.md)上使用。 - - `"bulk"` 方式不可以在开启外键约束检查时 (`foreign_key_checks = ON`) 对包含外键的表和被外键引用的表使用。 - - 当遇到不支持或不兼容的情况时,`"bulk"` 方式会回退到 `"standard"` 方式执行,并返回一条警告信息。你可以通过 [`tidb_last_txn_info`](#tidb_last_txn_info-从-v409-版本开始引入) 查看 `pipelined` 字段,如果为 `true` 则表示是使用 `"bulk"` 方式执行。 - - 以 `"bulk"` 方式执行超大事务时,事务耗时可能较长。对于这种模式的事务,其事务锁的最大 TTL 为 [`max-txn-ttl`](/tidb-configuration-file.md#max-txn-ttl) 与 24 小时中的较大值。此外,当事务执行时间超过 [`tidb_gc_max_wait_time`](#tidb_gc_max_wait_time-从-v610-版本开始引入) 设定值后,GC 可能会强制回滚事务,导致事务失败。 - - 以 `"bulk"` 方式执行事务时,事务的大小不受 TiDB 配置项 [`txn-total-size-limit`](/tidb-configuration-file.md#txn-total-size-limit) 的限制。 - - `"bulk"` 方式由 Pipelined DML 特性实现,详细设计和 GitHub issue 可见 [Pipelined DML](https://github.com/pingcap/tidb/blob/master/docs/design/2024-01-09-pipelined-DML.md) 和 [#50215](https://github.com/pingcap/tidb/issues/50215)。 + - `"bulk"` 表示使用 Pipelined DML 执行方式,适合于处理因大量数据写入导致 TiDB 内存使用过多的情况。更多信息,请参考 [Pipelined DML](/pipelined-dml.md)。 ### `tidb_enable_1pc` 从 v5.0 版本开始引入