Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: batch processing overview and pipelined dml #19021

Merged
merged 20 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions TOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,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)
Expand Down Expand Up @@ -939,6 +940,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)
Expand Down
97 changes: 97 additions & 0 deletions batch-processing.md
Original file line number Diff line number Diff line change
@@ -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 更快。
qiancai marked this conversation as resolved.
Show resolved Hide resolved
- 通过系统变量启用,无需修改 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 功能。建议选择上面描述的其它方案。
149 changes: 149 additions & 0 deletions pipelined-dml.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
---
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 内存总量,难以执行超大规模数据处理
qiancai marked this conversation as resolved.
Show resolved Hide resolved

启用此功能后,你可以:
ekexium marked this conversation as resolved.
Show resolved Hide resolved

- 执行不受 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-热点问题处理)。
qiancai marked this conversation as resolved.
Show resolved Hide resolved

## 相关配置

- 系统变量 [`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`](#tidb_last_txn_info-从-v409-版本开始引入),获取当前会话上一个事务的执行信息,包括是否使用了 Pipelined DML。
qiancai marked this conversation as resolved.
Show resolved Hide resolved
- 查看 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)
13 changes: 1 addition & 12 deletions system-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -1627,18 +1627,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` <span class="version-mark">从 v5.0 版本开始引入</span>

Expand Down
Loading