From 9d573a2bb23e6c40523202a7bd1a32082b4b3744 Mon Sep 17 00:00:00 2001 From: TomShawn <41534398+TomShawn@users.noreply.github.com> Date: Tue, 28 Feb 2023 18:10:27 +0800 Subject: [PATCH 01/13] Add ddl introduction docs --- ddl-introduction.md | 191 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 ddl-introduction.md diff --git a/ddl-introduction.md b/ddl-introduction.md new file mode 100644 index 0000000000000..22c2f519b1836 --- /dev/null +++ b/ddl-introduction.md @@ -0,0 +1,191 @@ +--- +title: Execution Principles and Best Practices of DDL Statements +summary: Learn about how DDL statements are implemented in TiDB, the online change process, and best practices. +--- + +# Execution Principles and Best Practices of DDL Statements + +This document provides an overview of the execution principles and best practices related to DDL statements in TiDB. The topics covered include the DDL Owner module and the online DDL change process. + +## DDL execution principles + +TiDB uses an online and asynchronous approach to executing DDL statements. This means that DML statements in other sessions are not blocked while DDL statements are being executed. In other words, you can change the definition of database objects using online and asynchronous DDL statements while your applications are running. + +### Types of DDL statements + +Based on whether a DDL statement blocks the user application during execution, DDL statements can be divided into the following types: + +- **Offline DDL statements**: When the database receives a DDL statement from the user, it first locks the database object to be modified, executes the metadata change, and blocks the user application from modifying data during the DDL execution. + +- **Online DDL statements**: When a DDL statement is executed in the database, a specific method is used to ensure that the statement does not block the user application. This allows the user to submit modifications during the DDL execution. The method also ensures the correctness and consistency of the corresponding database object during the execution process. + +Based on whether to operate the data included in the target DDL object, DDL statements can be divided into the following types: + +- **Logical DDL statements**: This type of DDL statements usually only modify the metadata of the database object, without processing the data stored in the object. For example, changing the table name or changing the column name. + + In TiDB, logical DDL statements are also referred to as "general DDL". These statements typically have a short execution time, often taking only a few tens of milliseconds or seconds to complete. As a result, they do not consume much system resource and do not affect the load on the application. + +- **Physical DDL statements**: This type of DDL statements not only modifies the metadata of the object to be changed, but also modifies the user data stored in the object. For example, when TiDB creates an index for a table, it not only changes the definition of the table, but also performs a full table scan to build the newly added index. + + In TiDB, physical DDL statements are also referred to as "reorg DDL", which stands for reorganization. Currently, physical DDL statements only include `ADD INDEX` and lossy column type changes (such as changing from an `INT` type to a `CHAR` type). These statements take a long time to execute, and the execution time is influenced by the amount of data in the table, the machine configuration, and the application load. + + Executing physical DDL statements can have an impact on the load of the application for two reasons. On the one hand, it requires CPU and I/O resources from TiKV to read data and write new data. On the other hand, the TiDB node where the DDL Owner is located needs to perform the corresponding computations, which consumes more CPU resources. Because TiDB does not currently support distributed execution of DDL statements, other TiDB nodes do not consume additional system resources during this process. + + > **Note:** + > + > The execution of physical DDL tasks is typically what causes the greatest impact on the user application. Therefore, to minimize this impact, the focus is on optimizing the design of physical DDL statements during execution. This helps to reduce the impact on the user application. + +### TiDB DDL module + +The TiDB DDL module incorporates the role of the DDL Owner (or Owner), which serves as a proxy for executing all DDL statements within the TiDB cluster. In the current implementation, only one TiDB node in the entire cluster can be elected as the Owner at any given time. Once elected, the worker started in that TiDB node can handle the DDL tasks in the cluster. + +TiDB uses the election mechanism of etcd to elect a node to host the Owner from multiple TiDB nodes. By default, each TiDB node can potentially be elected as the Owner (you can configure `run-ddl` to manage node participation in the election). The elected Owner node has a term, which it actively maintains by renewing the term. When the Owner node is down, another node can be re-elected as the new Owner through etcd and continue executing DDL tasks in the cluster. + +A simple illustration of the DDL Owner is as follows: + +![DDL Owner](/media/ddl-owner.png) + +You can use the `ADMIN SHOW DDL` statement to view the current DDL owner: + +```sql +ADMIN SHOW DDL; +``` + +```sql ++------------+--------------------------------------+---------------+--------------+--------------------------------------+-------+ +| SCHEMA_VER | OWNER_ID | OWNER_ADDRESS | RUNNING_JOBS | SELF_ID | QUERY | ++------------+--------------------------------------+---------------+--------------+--------------------------------------+-------+ +| 26 | 2d1982af-fa63-43ad-a3d5-73710683cc63 | 0.0.0.0:4000 | | 2d1982af-fa63-43ad-a3d5-73710683cc63 | | ++------------+--------------------------------------+---------------+--------------+--------------------------------------+-------+ +1 row in set (0.00 sec) +``` + +### How the Online DDL Asynchronous Change Works in TiDB + +From the beginning of its design, the TiDB DDL module has opted for an online asynchronous change mode, which enables users to modify their applications without experiencing any downtime. + +DDL changes involve transitioning from one state to another, typically from a "before change" state to an "after change" state. With online DDL changes, this transition occurs by introducing multiple small version states that are mutually compatible. During the execution of a DDL statement, TiDB nodes in the same cluster are allowed to have different small version changes, as long as the difference between the small versions of the change objects is not more than two versions. This is possible because adjacent small versions can be mutually compatible. + +In this way, evolving through multiple small versions ensures that metadata can be correctly synchronized across multiple TiDB nodes. This helps maintain the correctness and consistency of user transactions that involve changing data during the process. + +Taking `ADD INDEX` as an example, the entire process of state change is as follows: + +``` +absent -> delete only -> write only -> write reorg -> public +``` + +For users, the newly created index is unavailable before the `public` state. + + +
+ +在 v6.2.0 之前,TiDB SQL 层中处理异步 Schema 变更的基本流程如下: + +1. MySQL Client 发送给 TiDB server 一个 DDL 操作请求。 +1. MySQL Client sends a DDL request to TiDB server. + +2. 某个 TiDB server 收到请求(即 TiDB server 的 MySQL Protocol 层对请求进行解析优化),然后发送到 TiDB SQL 层进行执行。 +2. A TiDB server receives the request (that is, the MySQL Protocol layer of the TiDB server parses and optimizes the request), and then sends it to the TiDB SQL layer for execution. + + TiDB SQL 层接到 DDL 请求后,会启动 `start job` 模块根据请求将请求封装成特定的 DDL Job(即 DDL 任务),然后将此 Job 按语句类型分类,分别存储到 KV 层的对应 DDL Job 队列,并通知自身对应的 worker 有 Job 需要处理。 + + After the SQL layer of TiDB receives the DDL request, it starts the `start job` module to encapsulate the request into a specific DDL Job (that is, a DDL task), and then stores this Job in the corresponding DDL Job queue in the KV layer according to the statement type, and notifies the corresponding worker that there is a Job that needs to be processed. + +3. 接收到处理 Job 通知的 worker,会判断自身是否处于 DDL Owner 的角色。如果是 Owner 角色则直接处理此 Job。如果没有处于 Owner 角色则退出不做任何处理。 +3. When receiving the notification to process the Job, the worker determines whether it is in the role of the DDL Owner. If it is the Owner role, it directly processes the Job. If it is not the Owner role, it exits without performing any processing. + + 假设某台 TiDB server 不是 Owner 角色,那么其他某个节点一定有一个是 Owner。处于 Owner 角色的节点的 worker 通过定期检测机制来检查是否有 Job 可以被执行。如果发现有 Job ,那么 worker 就会处理该 Job。 + + If a TiDB server is not the Owner role, then another node must be the Owner. The worker of the node in the Owner role periodically checks whether there is a Job that can be executed. If such a Job is found, the worker will process the Job. + +4. Worker 处理完 Job 后,会将此 Job 从 KV 层对应的 Job queue 中移除,并放入 `job history queue`。之前封装 Job 的 `start job` 模块会定期在 `job history queue` 中查看是否有已经处理完成的 Job 的 ID。如果有,则这个 Job 对应的整个 DDL 操作结束执行。 +4. + +5. TiDB server 将 DDL 处理结果返回至 MySQL Client。 + +在 TiDB v6.2.0 前,该 DDL 执行框架存在以下限制: + +- TiKV 集群中只有 `general job queue` 和 `add index job queue` 两个队列,分别处理逻辑 DDL 和物理 DDL。 +- DDL Owner 总是以先入先出的方式处理 DDL Job。 +- DDL Owner 每次只能执行一个同种类型(逻辑或物理)的 DDL 任务,这个约束较为严格。 + +这些限制可能会导致一些“非预期”的 DDL 阻塞行为。具体可以参考 [SQL FAQ - DDL 执行](/faq/sql-faq.md#ddl-执行)。 + +
+
+ +在 TiDB v6.2 之前,由于 Owner 每次只能执行一个同种类型(逻辑或物理)的 DDL 任务,这个约束较为严格,同时影响用户体验。 + +当 DDL 任务之间不存在相关依赖时,并行执行并不会影响数据正确性和一致性。例如:用户 A 在 `T1` 表上增加一个索引,同时用户 B 从 `T2` 表删除一列。这两条 DDL 语句可以并行执行。 + +为了提升 DDL 执行的用户体验,从 v6.2.0 起,TiDB 对原有的 DDL Owner 角色进行了升级,使得 Owner 能对 DDL 任务做相关性判断,判断逻辑如下: + ++ 涉及同一张表的 DDL 相互阻塞。 ++ `DROP DATABASE` 和数据库内所有对象的 DDL 互相阻塞。 ++ 涉及不同表的加索引和列类型变更可以并发执行。 ++ 逻辑 DDL 需要等待之前正在执行的逻辑 DDL 执行完才能执行。 ++ 其他情况下 DDL 可以根据 Concurrent DDL 并行度可用情况确定是否可以执行。 + +具体来说,TiDB 在 v6.2.0 中对 DDL 执行框架进行了如下升级: + ++ DDL Owner 能够根据以上判断逻辑并行执行 DDL 任务。 ++ 改善了 DDL Job 队列先入先出的问题。DDL Owner 不再选择当前队列最前面的 DDL Job,而是选择当前可以执行的 DDL Job。 ++ 扩充了处理物理 DDL 的 worker 数量,使得能够并行地添加多个物理 DDL。 + + 因为 TiDB 中所有支持的 DDL 任务都是以在线变更的方式来实现的,TiDB 通过 Owner 即可对新的 DDL Job 进行相关性判断,并根据相关性结果进行 DDL 任务的调度,从而使分布式数据库实现了和传统数据库中 DDL 并发相同的效果。 + +并发 DDL 框架的实现进一步加强了 TiDB 中 DDL 语句的执行能力,并更符合商用数据库的使用习惯。 + +
+
+ +## 最佳实践 + +### 通过系统变量来平衡物理 DDL 的执行速度与对业务负载的影响 + +执行物理 DDL(包括添加索引或列类型变更)时,适当调整以下系统变量可以平衡 DDL 执行速度与对业务负载的影响: + +- [`tidb_ddl_reorg_worker_cnt`](/system-variables.md#tidb_ddl_reorg_worker_cnt):这个变量用来设置 DDL 操作 reorg worker 的数量,控制回填的并发度。 + +- [`tidb_ddl_reorg_batch_size`](/system-variables.md#tidb_ddl_reorg_batch_size):这个变量用来设置 DDL 操作 `re-organize` 阶段的 batch size,以控制回填的数据量。 + + 推荐值: + + - 在无其他负载情况下,如需让 `ADD INDEX` 尽快完成,可以将 `tidb_ddl_reorg_worker_cnt` 和 `tidb_ddl_reorg_batch_size` 的值适当调大,例如将两个变量值分别调为 `20` 和 `2048`。 + - 在有其他负载情况下,如需让 `ADD INDEX` 尽量不影响其他业务,可以将 `tidb_ddl_reorg_worker_cnt` 和 `tidb_ddl_reorg_batch_size` 适当调小,例如将两个变量值分别调为 `4` 和 `256`。 + +> **建议:** +> +> - 以上两个变量均可以在 DDL 任务执行过程中动态调整,并且在下一个 batch 生效。 +> - 根据 DDL 操作的类型,并结合业务负载压力,选择合适的时间点执行,例如建议在业务负载比较低的情况运行 `ADD INDEX` 操作。 +> - 由于添加索引的时间跨度较长,发送相关的指令后,TiDB 会在后台执行任务,TiDB server 挂掉不会影响继续执行。 + +### 并发发送 DDL 请求实现快速建大量表 + +一个建表的操作耗时大约 50 毫秒。受框架的限制,建表耗时可能更长。 + +为了更快地建表,推荐通过并发发送多个 DDL 请求以达到最快建表速度。如果串行地发送 DDL 请求,并且没有发给 Owner 节点,则建表速度会很慢。 + +### 在一条 `ALTER` 语句中进行多次变更 + +自 v6.2.0 起,TiDB 支持在一条 `ALTER` 语句中修改一张表的多个模式对象(如列、索引),同时保证整个语句的原子性。因此推荐在一条 `ALTER` 语句中进行多次变更。 + +### 检查读写性能 + +在添加索引时,回填数据阶段会对集群造成一定的读写压力。在 `ADD INDEX` 的命令发送成功后,并且在 `write reorg` 阶段,建议检查 Grafana 面板上 TiDB 和 TiKV 读写相关的性能指标,以及业务响应时间,来确定 `ADD INDEX` 操作对集群是否造成影响。 + +## DDL 相关的命令介绍 + +- `ADMIN SHOW DDL`:用于查看 TiDB DDL 的状态,包括当前 schema 版本号、DDL Owner 的 DDL ID 和地址、正在执行的 DDL 任务和 SQL、当前 TiDB 实例的 DDL ID。详情参阅 [`ADMIN SHOW DDL`](/sql-statements/sql-statement-admin-show-ddl.md#admin-show-ddl)。 + +- `ADMIN SHOW DDL JOBS`:查看集群环境中的 DDL 任务运行中详细的状态。详情参阅 [`ADMIN SHOW DDL JOBS`](/sql-statements/sql-statement-admin-show-ddl.md#admin-show-ddl-jobs)。 + +- `ADMIN SHOW DDL JOB QUERIES job_id [, job_id]`:用于查看 job_id 对应的 DDL 任务的原始 SQL 语句。详情参阅 [`ADMIN SHOW DDL JOB QUERIES`](/sql-statements/sql-statement-admin-show-ddl.md#admin-show-ddl-job-queries)。 + +- `ADMIN CANCEL DDL JOBS job_id, [, job_id]`:用于取消已经提交但未执行完成的 DDL 任务。取消完成后,执行 DDL 任务的 SQL 语句会返回 `ERROR 8214 (HY000): Cancelled DDL job` 错误。 + + 取消一个已经执行完成的 DDL 任务会在 RESULT 列看到 `DDL Job:90 not found` 的错误,表示该任务已从 DDL 等待队列中被移除。 + +## 常见问题 + +DDL 语句执行相关的常见问题,参考 [SQL FAQ - DDL 执行](/faq/sql-faq.md#ddl-执行)。 From 5ce4668452f325c7b8f1ed23bc84290b2ab3b5b7 Mon Sep 17 00:00:00 2001 From: TomShawn <41534398+TomShawn@users.noreply.github.com> Date: Wed, 1 Mar 2023 11:49:53 +0800 Subject: [PATCH 02/13] add more translation --- ddl-introduction.md | 64 ++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/ddl-introduction.md b/ddl-introduction.md index 22c2f519b1836..40f23338deae9 100644 --- a/ddl-introduction.md +++ b/ddl-introduction.md @@ -79,62 +79,54 @@ For users, the newly created index is unavailable before the `public` state.
-在 v6.2.0 之前,TiDB SQL 层中处理异步 Schema 变更的基本流程如下: +Before v6.2.0, the process of handling asynchronous schema changes in the TiDB SQL layer is as follows: -1. MySQL Client 发送给 TiDB server 一个 DDL 操作请求。 -1. MySQL Client sends a DDL request to TiDB server. +1. MySQL Client sends a DDL request to the TiDB server. -2. 某个 TiDB server 收到请求(即 TiDB server 的 MySQL Protocol 层对请求进行解析优化),然后发送到 TiDB SQL 层进行执行。 -2. A TiDB server receives the request (that is, the MySQL Protocol layer of the TiDB server parses and optimizes the request), and then sends it to the TiDB SQL layer for execution. +2. After receiving the request, a TiDB server parses and optimizes the request at the MySQL Protocol layer, and then sends it to the TiDB SQL layer for execution. - TiDB SQL 层接到 DDL 请求后,会启动 `start job` 模块根据请求将请求封装成特定的 DDL Job(即 DDL 任务),然后将此 Job 按语句类型分类,分别存储到 KV 层的对应 DDL Job 队列,并通知自身对应的 worker 有 Job 需要处理。 + Once the SQL layer of TiDB receives the DDL request, it starts the `start job` module to encapsulate the request into a specific DDL Job (that is, a DDL task), and then stores this Job in the corresponding DDL Job queue in the KV layer based on the statement type. The corresponding worker is notified of the Job that requires processing. - After the SQL layer of TiDB receives the DDL request, it starts the `start job` module to encapsulate the request into a specific DDL Job (that is, a DDL task), and then stores this Job in the corresponding DDL Job queue in the KV layer according to the statement type, and notifies the corresponding worker that there is a Job that needs to be processed. +3. When receiving the notification to process the Job, the worker determines whether it is the role of the DDL Owner. If it is the Owner role, it directly processes the Job. Otherwise, it exits without performing any processing. -3. 接收到处理 Job 通知的 worker,会判断自身是否处于 DDL Owner 的角色。如果是 Owner 角色则直接处理此 Job。如果没有处于 Owner 角色则退出不做任何处理。 -3. When receiving the notification to process the Job, the worker determines whether it is in the role of the DDL Owner. If it is the Owner role, it directly processes the Job. If it is not the Owner role, it exits without performing any processing. + If a TiDB server is not the Owner role, then another node must be the Owner. The worker of the node in the Owner role periodically checks whether there is an available Job that can be executed. If such a Job is identified, the worker will process the Job. - 假设某台 TiDB server 不是 Owner 角色,那么其他某个节点一定有一个是 Owner。处于 Owner 角色的节点的 worker 通过定期检测机制来检查是否有 Job 可以被执行。如果发现有 Job ,那么 worker 就会处理该 Job。 +4. After the worker processes the Job, it removes the Job from the Job queue in the KV layer and places it in the `job history queue`. The `start job` module that encapsulated the Job will periodically check the ID of the Job in the `job history queue` to see whether it has been processed. If so, the entire DDL operation corresponding to the Job ends. - If a TiDB server is not the Owner role, then another node must be the Owner. The worker of the node in the Owner role periodically checks whether there is a Job that can be executed. If such a Job is found, the worker will process the Job. +5. TiDB server returns the DDL processing result to the MySQL Client. -4. Worker 处理完 Job 后,会将此 Job 从 KV 层对应的 Job queue 中移除,并放入 `job history queue`。之前封装 Job 的 `start job` 模块会定期在 `job history queue` 中查看是否有已经处理完成的 Job 的 ID。如果有,则这个 Job 对应的整个 DDL 操作结束执行。 -4. +Before TiDB v6.2.0, the DDL execution framework had the following limitations: -5. TiDB server 将 DDL 处理结果返回至 MySQL Client。 +- The TiKV cluster only has two queues: `general job queue` and `add index job queue`, which handle logical DDL and physical DDL, respectively. +- The DDL Owner always processes DDL Jobs in a first-in-first-out way. +- The DDL Owner can only execute one DDL task of the same type (logical or physical) at a time, which is relatively strict. -在 TiDB v6.2.0 前,该 DDL 执行框架存在以下限制: - -- TiKV 集群中只有 `general job queue` 和 `add index job queue` 两个队列,分别处理逻辑 DDL 和物理 DDL。 -- DDL Owner 总是以先入先出的方式处理 DDL Job。 -- DDL Owner 每次只能执行一个同种类型(逻辑或物理)的 DDL 任务,这个约束较为严格。 - -这些限制可能会导致一些“非预期”的 DDL 阻塞行为。具体可以参考 [SQL FAQ - DDL 执行](/faq/sql-faq.md#ddl-执行)。 +These limitations might lead to some "unintended" DDL blocking behavior. For more details, see [SQL FAQ - DDL Execution](/faq/sql-faq.md#ddl-execution).
-
+
-在 TiDB v6.2 之前,由于 Owner 每次只能执行一个同种类型(逻辑或物理)的 DDL 任务,这个约束较为严格,同时影响用户体验。 +Before TiDB v6.2, because the Owner can only execute one DDL task of the same type (logical or physical) at a time, which is relatively strict, and affects the user experience. -当 DDL 任务之间不存在相关依赖时,并行执行并不会影响数据正确性和一致性。例如:用户 A 在 `T1` 表上增加一个索引,同时用户 B 从 `T2` 表删除一列。这两条 DDL 语句可以并行执行。 +If there is no dependency between DDL tasks, parallel execution does not affect data correctness and consistency. For example, user A adds an index to the `T1` table, while user B deletes a column from the `T2` table. These two DDL statements can be executed in parallel. -为了提升 DDL 执行的用户体验,从 v6.2.0 起,TiDB 对原有的 DDL Owner 角色进行了升级,使得 Owner 能对 DDL 任务做相关性判断,判断逻辑如下: +To improve the user experience of DDL execution, starting from v6.2.0, TiDB enables the Owner to determine the relevance of DDL tasks. The logic is as follows: -+ 涉及同一张表的 DDL 相互阻塞。 -+ `DROP DATABASE` 和数据库内所有对象的 DDL 互相阻塞。 -+ 涉及不同表的加索引和列类型变更可以并发执行。 -+ 逻辑 DDL 需要等待之前正在执行的逻辑 DDL 执行完才能执行。 -+ 其他情况下 DDL 可以根据 Concurrent DDL 并行度可用情况确定是否可以执行。 ++ DDL statements to be performed on the same table are mutually blocked. ++ `DROP DATABASE` and DDL statements that affect all objects in the database are mutually blocked. ++ Adding indexes and column type changes on different tables can be executed concurrently. ++ A logical DDL statement must wait for the previous logical DDL statement to be executed before it can be executed. ++ In other cases, DDL can be executed based on the level of availability for concurrent DDL execution. -具体来说,TiDB 在 v6.2.0 中对 DDL 执行框架进行了如下升级: +In specific, TiDB has upgraded the DDL execution framework in v6.2.0 in the following aspects: -+ DDL Owner 能够根据以上判断逻辑并行执行 DDL 任务。 -+ 改善了 DDL Job 队列先入先出的问题。DDL Owner 不再选择当前队列最前面的 DDL Job,而是选择当前可以执行的 DDL Job。 -+ 扩充了处理物理 DDL 的 worker 数量,使得能够并行地添加多个物理 DDL。 ++ The DDL Owner can execute DDL tasks in parallel based on the preceding logic. ++ The first-in-first-out issue in the DDL Job queue has been addressed. The DDL Owner no longer selects the first Job in the queue, but instead selects the Job that can be executed at the current time. ++ The number of workers that handle physical DDL has been increased, enabling multiple physical DDLs to be executed in parallel. - 因为 TiDB 中所有支持的 DDL 任务都是以在线变更的方式来实现的,TiDB 通过 Owner 即可对新的 DDL Job 进行相关性判断,并根据相关性结果进行 DDL 任务的调度,从而使分布式数据库实现了和传统数据库中 DDL 并发相同的效果。 + Because all DDL tasks in TiDB are implemented using an online change approach, TiDB can determine the relevance of new DDL Jobs through the Owner, and schedule DDL tasks based on this information. This approach enables the distributed database to achieve the same level of DDL concurrency as traditional databases. -并发 DDL 框架的实现进一步加强了 TiDB 中 DDL 语句的执行能力,并更符合商用数据库的使用习惯。 +The concurrent DDL framework enhances the execution capability of DDL statements in TiDB, making it more compatible with the usage patterns of commercial databases.
From 675aa51bc48d2fdc852387ce1bd590dceaba77b9 Mon Sep 17 00:00:00 2001 From: TomShawn <41534398+TomShawn@users.noreply.github.com> Date: Wed, 1 Mar 2023 15:12:38 +0800 Subject: [PATCH 03/13] add more translation --- ddl-introduction.md | 54 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/ddl-introduction.md b/ddl-introduction.md index 40f23338deae9..0562ada2ce1a1 100644 --- a/ddl-introduction.md +++ b/ddl-introduction.md @@ -131,53 +131,53 @@ The concurrent DDL framework enhances the execution capability of DDL statements
-## 最佳实践 +## Best practices -### 通过系统变量来平衡物理 DDL 的执行速度与对业务负载的影响 +### Balance the physical DDL execution speed and the impact on application load through system variables -执行物理 DDL(包括添加索引或列类型变更)时,适当调整以下系统变量可以平衡 DDL 执行速度与对业务负载的影响: +When executing physical DDLs (including adding indexes or column type changes), you can adjust the values of the following system variables to balance the speed of DDL execution and the impact on application load: -- [`tidb_ddl_reorg_worker_cnt`](/system-variables.md#tidb_ddl_reorg_worker_cnt):这个变量用来设置 DDL 操作 reorg worker 的数量,控制回填的并发度。 +- [`tidb_ddl_reorg_worker_cnt`](/system-variables.md#tidb_ddl_reorg_worker_cnt): This variable sets the number of reorg workers for a DDL operation, which controls the concurrency of backfilling. -- [`tidb_ddl_reorg_batch_size`](/system-variables.md#tidb_ddl_reorg_batch_size):这个变量用来设置 DDL 操作 `re-organize` 阶段的 batch size,以控制回填的数据量。 +- [`tidb_ddl_reorg_batch_size`](/system-variables.md#tidb_ddl_reorg_batch_size): This variable sets the batch size for a DDL operation in the `re-organize` phase, which controls the amount of data to be backfilled. - 推荐值: + Recommended values: - - 在无其他负载情况下,如需让 `ADD INDEX` 尽快完成,可以将 `tidb_ddl_reorg_worker_cnt` 和 `tidb_ddl_reorg_batch_size` 的值适当调大,例如将两个变量值分别调为 `20` 和 `2048`。 - - 在有其他负载情况下,如需让 `ADD INDEX` 尽量不影响其他业务,可以将 `tidb_ddl_reorg_worker_cnt` 和 `tidb_ddl_reorg_batch_size` 适当调小,例如将两个变量值分别调为 `4` 和 `256`。 + - If there is no other load, you can increase the values of `tidb_ddl_reorg_worker_cnt` and `tidb_ddl_reorg_batch_size` to speed up the `ADD INDEX` operation. For example, you can set the values of the two variables to `20` and `2048`, respectively. + - If there is other load, you can decrease the values of `tidb_ddl_reorg_worker_cnt` and `tidb_ddl_reorg_batch_size` to minimize the impact on other application. For example, you can set the values of the these variables to `4` and `256`, respectively. -> **建议:** +> **Tip:** > -> - 以上两个变量均可以在 DDL 任务执行过程中动态调整,并且在下一个 batch 生效。 -> - 根据 DDL 操作的类型,并结合业务负载压力,选择合适的时间点执行,例如建议在业务负载比较低的情况运行 `ADD INDEX` 操作。 -> - 由于添加索引的时间跨度较长,发送相关的指令后,TiDB 会在后台执行任务,TiDB server 挂掉不会影响继续执行。 +> - The preceding two variables can be dynamically adjusted during the execution of a DDL task, and take effect in the next transaction batch. +> - Choose the appropriate time to execute the DDL operation based on the type of the operation and the application load pressure. For example, it is recommended to run the `ADD INDEX` operation when the application load is low. +> - Because the duration of adding an index is relatively long, TiDB will execute the task in the background after the command is sent. If the TiDB server is down, the execution will not be affected. -### 并发发送 DDL 请求实现快速建大量表 +### Quickly create many tables by concurrently sending DDL requests -一个建表的操作耗时大约 50 毫秒。受框架的限制,建表耗时可能更长。 +A table creation operation takes about 50 milliseconds. The actual time taken to create a table might be longer because of the framework limitations. -为了更快地建表,推荐通过并发发送多个 DDL 请求以达到最快建表速度。如果串行地发送 DDL 请求,并且没有发给 Owner 节点,则建表速度会很慢。 +To create tables faster, it is recommended to send multiple DDL requests concurrently to achieve the fastest table creation speed. If you send DDL requests serially and do not send them to the Owner node, the table creation speed will be very slow. -### 在一条 `ALTER` 语句中进行多次变更 +### Make multiple changes in a single `ALTER` statement -自 v6.2.0 起,TiDB 支持在一条 `ALTER` 语句中修改一张表的多个模式对象(如列、索引),同时保证整个语句的原子性。因此推荐在一条 `ALTER` 语句中进行多次变更。 +Starting from v6.2.0, TiDB supports modifying multiple schema objects (such as columns and indexes) of a table in a single `ALTER` statement while ensuring the atomicity of the entire statement. Therefore, it is recommended to make multiple changes in a single `ALTER` statement. -### 检查读写性能 +### Check the read and write performance -在添加索引时,回填数据阶段会对集群造成一定的读写压力。在 `ADD INDEX` 的命令发送成功后,并且在 `write reorg` 阶段,建议检查 Grafana 面板上 TiDB 和 TiKV 读写相关的性能指标,以及业务响应时间,来确定 `ADD INDEX` 操作对集群是否造成影响。 +When TiDB is adding an index, the phase of backfilling data will cause read and write pressure on the cluster. After the `ADD INDEX` command is sent and the `write reorg` phase starts, it is recommended to check the read and write performance metrics of TiDB and TiKV on the Grafana dashboard and the application response time, to determine whether the `ADD INDEX` operation affects the cluster. -## DDL 相关的命令介绍 +## DDL-related commands -- `ADMIN SHOW DDL`:用于查看 TiDB DDL 的状态,包括当前 schema 版本号、DDL Owner 的 DDL ID 和地址、正在执行的 DDL 任务和 SQL、当前 TiDB 实例的 DDL ID。详情参阅 [`ADMIN SHOW DDL`](/sql-statements/sql-statement-admin-show-ddl.md#admin-show-ddl)。 +- `ADMIN SHOW DDL`: Used to view the status of TiDB DDL operations, including the current schema version number, the DDL ID and address of the DDL Owner, the DDL task and SQL being executed, and the DDL ID of the current TiDB instance. For details, see [`ADMIN SHOW DDL`](/sql-statements/sql-statement-admin-show-ddl.md#admin-show-ddl). -- `ADMIN SHOW DDL JOBS`:查看集群环境中的 DDL 任务运行中详细的状态。详情参阅 [`ADMIN SHOW DDL JOBS`](/sql-statements/sql-statement-admin-show-ddl.md#admin-show-ddl-jobs)。 +- `ADMIN SHOW DDL JOBS`: Used to view the detailed status of DDL tasks running in the cluster environment. For details, see [`ADMIN SHOW DDL JOBS`](/sql-statements/sql-statement-admin-show-ddl.md#admin-show-ddl-jobs). -- `ADMIN SHOW DDL JOB QUERIES job_id [, job_id]`:用于查看 job_id 对应的 DDL 任务的原始 SQL 语句。详情参阅 [`ADMIN SHOW DDL JOB QUERIES`](/sql-statements/sql-statement-admin-show-ddl.md#admin-show-ddl-job-queries)。 +- `ADMIN SHOW DDL JOB QUERIES job_id [, job_id]`: Used to view the original SQL statement of the DDL task corresponding to the `job_id`. For details, see [`ADMIN SHOW DDL JOB QUERIES`](/sql-statements/sql-statement-admin-show-ddl.md#admin-show-ddl-job-queries). -- `ADMIN CANCEL DDL JOBS job_id, [, job_id]`:用于取消已经提交但未执行完成的 DDL 任务。取消完成后,执行 DDL 任务的 SQL 语句会返回 `ERROR 8214 (HY000): Cancelled DDL job` 错误。 +- `ADMIN CANCEL DDL JOBS job_id, [, job_id]`: Used to cancel DDL tasks that have been submitted but not completed. After the cancellation is completed, the SQL statement that executes the DDL task returns the `ERROR 8214 (HY000): Cancelled DDL job` error. - 取消一个已经执行完成的 DDL 任务会在 RESULT 列看到 `DDL Job:90 not found` 的错误,表示该任务已从 DDL 等待队列中被移除。 + If a completed DDL task is canceled, you can see the `DDL Job:90 not found` error in the `RESULT` column, which means that the task has been removed from the DDL waiting queue. -## 常见问题 +## Common questions -DDL 语句执行相关的常见问题,参考 [SQL FAQ - DDL 执行](/faq/sql-faq.md#ddl-执行)。 +For common questions about DDL execution, see [SQL FAQ - DDL execution](/faq/sql-faq.md#ddl-execution). From bd176646c78dc2969ddab4ee791c76288d8c7195 Mon Sep 17 00:00:00 2001 From: Ran Date: Thu, 2 Mar 2023 15:25:52 +0800 Subject: [PATCH 04/13] translate sql-faq and show-ddl Signed-off-by: Ran --- faq/sql-faq.md | 68 +++++++++++++++++-- .../sql-statement-admin-show-ddl.md | 49 +++++++++---- 2 files changed, 100 insertions(+), 17 deletions(-) diff --git a/faq/sql-faq.md b/faq/sql-faq.md index 926d65c1ed591..c0eb3ba9f4ca8 100644 --- a/faq/sql-faq.md +++ b/faq/sql-faq.md @@ -237,9 +237,41 @@ TiDB supports multiple ways to override the default query optimizer behavior, in SELECT column_name FROM table_name USE INDEX(index_name)WHERE where_condition; ``` -## Why the `Information schema is changed` error is reported? +## DDL Execution -TiDB handles the SQL statement using the `schema` of the time and supports online asynchronous DDL change. A DML statement and a DDL statement might be executed at the same time and you must ensure that each statement is executed using the same `schema`. Therefore, when the DML operation meets the ongoing DDL operation, the `Information schema is changed` error might be reported. Some improvements have been made to prevent too many error reportings during the DML operation. +This section lists issues related to DDL statement execution. For detailed explanations on the DDL execution principle, refer to [Execution Principles and Best Practices of DDL Statements](/ddl-introduction.md). + +### How long does it take to perform various DDL operations? + +Assuming that DDL operations are not blocked, each TiDB server can update the schema version normally, and the DDL owner node is running normally. In this case, the estimated time for various DDL operations is as follows: + +| DDL Operation Type | Estimated Time | +|:----------|:-----------| +| Reorg DDL, such as `ADD INDEX`, `MODIFY COLUMN` (Reorg type data changes) | Depends on the amount of data, system load, and DDL parameter settings. | +| General DDL (DDL types other than Reorg), such as `CREATE DATABASE`, `CREATE TABLE`, `DROP DATABASE`, `DROP TABLE`, `TRUNCATE TABLE`, `ALTER TABLE ADD`, `ALTER TABLE DROP`, `MODIFY COLUMN` (only changes metadata), `DROP INDEX` | About 1 second | + +> **Note:** +> +> The above are estimated times for the operations. The actual time might be different. + +### Possible reasons why DDL execution is slow + +- In a user session, if there is a non-auto-commit DML statement before a DDL statement, and if the commit operation of the DML statement is slow, it will cause the DDL statement to execute slowly. That is, TiDB commits the uncommitted DML statement before executing the DDL statement. + +- When multiple DDL statements are executed together, the execution of the later DDL statements might be slower because they might need to wait in queue. Queuing scenarios include: + + - The same type of DDL statements need to be queued. For example, both `CREATE TABLE` and `CREATE DATABASE` are general DDL statements, so when both operations are executed at the same time, they need to be queued. Since TiDB v6.2.0, parallel DDL statements are supported, but to avoid DDL execution using too many TiDB computing resources, there is also concurrency limit. Queuing occurs when DDL exceeds the concurrency limit. + - The DDL operations performed on the same table have a dependency relationship between. The later DDL statement needs to wait for the previous DDL operation to complete. + +- After the cluster is started normally, the execution time of the first DDL operation might be relatively long because the DDL module is electing the DDL owner. + +- TiDB is terminated, which causes TiDB to not able to communicate with PD normally (including power-off situations). Or TiDB is terminated by the `kill -9` command, which causes TiDB to not timely clear the registration data from PD. + +- A communication problem occurs between a certain TiDB node in the cluster and PD or TiKV, which makes TiDB not able to obtain the latest version information in time. + +### What triggers the `Information schema is changed` error? + +When executing SQL statements, TiDB determines the schema version of an object based on the isolation level and processes the SQL statement accordingly. TiDB also supports online asynchronous DDL changes. When executing DML statements, there may be DDL statements being executed at the same time, and you need to ensure that each SQL statement is executed on the same schema. Therefore, when executing DML, if a DDL operation is ongoing, TiDB might report an `Information schema is changed` error. Starting from v6.4.0, TiDB has implemented a [metadata lock mechanism](/metadata-lock.md), which allows the coordinated execution of DML statements and DDL schema changes, avoiding most `Information schema is changed` errors. Now, there are still a few causes for this error reporting: @@ -256,19 +288,45 @@ In the preceding causes, only Cause 1 is related to tables. Cause 1 and Cause 2 > + For each DDL operation, the number of `schema` version changes is the same with the number of corresponding `schema state` version changes. > + Different DDL operations cause different number of `schema` version changes. For example, the `CREATE TABLE` statement causes one `schema` version change while the `ADD COLUMN` statement causes four. -## What are the causes of the "Information schema is out of date" error? +### What are the causes of the "Information schema is out of date" error? -When executing a DML statement, if TiDB fails to load the latest schema within a DDL lease (45s by default), the `Information schema is out of date` error might occur. Possible causes are: +Before TiDB v6.5.0, when executing a DML statement, if TiDB fails to load the latest schema within a DDL lease (45s by default), the `Information schema is out of date` error might occur. Possible causes are: - The TiDB instance that executed this DML was killed, and the transaction execution corresponding to this DML statement took longer than a DDL lease. When the transaction was committed, the error occurred. - TiDB failed to connect to PD or TiKV while executing this DML statement. As a result, TiDB failed to load schema within a DDL lease or disconnected from PD due to the keepalive setting. -## Error is reported when executing DDL statements under high concurrency? +### Error is reported when executing DDL statements under high concurrency? When you execute DDL statements (such as creating tables in batches) under high concurrency, a very few of these statements might fail because of key conflicts during the concurrent execution. It is recommended to keep the number of concurrent DDL statements under 20. Otherwise, you need to retry the failed statements from the client. +### Why is DDL execution blocked? + +Before TiDB v6.2.0, TiDB allocates DDL statements to two first-in-first-out queues based on the type of DDL statements. More specifically, Reorg DDLs go to the Reorg queue and General DDLs go to the general queue. Because of the first-in-first-out limitation and the need for serial execution of DDL statements on the same table, multiple DDL statements might be blocked during execution. + +For example, consider the following DDL statements: + +- DDL 1: `CREATE INDEX idx on t(a int);` +- DDL 2: `ALTER TABLE t ADD COLUMN b int;` +- DDL 3: `CREATE TABLE t1(a int);` + +Due to the limitation of the first-in-first-out queue, DDL 3 must wait for DDL 2 to execute. Also, because DDL statements on the same table need to be executed in serial, DDL 2 must for DDL 1 to execute. Therefore, DDL 3 needs to wait for DDL 1 to be executed first, even if they operate on different tables. + +Starting from TiDB v6.2.0, the TiDB DDL module uses a concurrent framework. In the concurrent framework, there is no longer the limitation of the first-in-first-out queue. Instead, TiDB picks up the DDL task that can be executed from all DDL tasks. Additionally, the number of Reorg workers has been expanded, approximately to `CPU/4` per node. This allows TiDB to build indexes for multiple tables simultaneously in the concurrent framework. + +Whether your cluster is a new cluster or an upgraded cluster from an earlier version, TiDB automatically uses the concurrent framework in TiDB v6.2 and later versions. You do not need to make manual adjustments. + +### Identify the cause of stuck DDL execution + +1. Eliminate other reasons that make the DDL statement execution slow. +2. Use one of the following methods to identify the DDL owner node: + - Use `curl http://{TiDBIP}:10080/info/all` to obtain the owner of the current cluster. + - View the owner during a specific time period from the monitoring dashboard **DDL** > **DDL META OPM**. + +- If the owner does not exist, try manually triggering owner election with: `curl -X POST http://{TiDBIP}:10080/ddl/owner/resign`. +- If the owner exists, export the Goroutine stack and check for the possible stuck location. + ## SQL optimization ### TiDB execution plan description diff --git a/sql-statements/sql-statement-admin-show-ddl.md b/sql-statements/sql-statement-admin-show-ddl.md index ac0ed77c28abf..a451d55f62856 100644 --- a/sql-statements/sql-statement-admin-show-ddl.md +++ b/sql-statements/sql-statement-admin-show-ddl.md @@ -24,7 +24,7 @@ WhereClauseOptional ::= ### `ADMIN SHOW DDL` -To view the currently running DDL jobs, use `ADMIN SHOW DDL`: +To view the status of the currently running DDL jobs, use `ADMIN SHOW DDL`. The output includes the current schema version, the DDL ID and address of the owner, the running DDL jobs and SQL statements, and the DDL ID of the current TiDB instance. {{< copyable "sql" >}} @@ -44,7 +44,32 @@ mysql> ADMIN SHOW DDL; ### `ADMIN SHOW DDL JOBS` -To view all the results in the current DDL job queue (including tasks that are running and waiting to be run) and the last ten results in the completed DDL job queue, use `ADMIN SHOW DDL JOBS`: +The `ADMIN SHOW DDL JOBS` statement is used to view all the results in the current DDL job queue, including running and queuing tasks, as well as the latest ten results in the completed DDL job queue. The returned result fields are described as follows: + +- `JOB_ID`: Each DDL operation corresponds to a DDL job. `JOB_ID` is globally unique. +- `DB_NAME`: The name of the database where the DDL operation is performed. +- `TABLE_NAME`: The name of the table where the DDL operation is performed. +- `JOB_TYPE`: The type of DDL operation. +- `SCHEMA_STATE`: The current state of the schema object that the DDL operates on. If `JOB_TYPE` is `ADD INDEX`, it is the state of the index; if `JOB_TYPE` is `ADD COLUMN`, it is the state of the column; if `JOB_TYPE` is `CREATE TABLE`, it is the state of the table. Common states include the following: + + - `none`: indicates that it does not exist. Generally, after the `DROP` operation or after the `CREATE` operation fails and rolls back, it will become the `none` state. + - `delete only`, `write only`, `delete reorganization`, `write reorganization`: These four states are intermediate states. For their specific meanings, refer to [How the Online DDL Asynchronous Change Works in TiDB](/ddl-introduction.md#how-the-online-ddl-asynchronous-change-works-in-tidb). As the intermediate state conversion is fast, these states are generally not visible during operation. Only when performing `ADD INDEX` operation can the `write reorganization` state be seen, indicating that index data is being added. + - `public`: indicates that it exists and is available to users. Generally, after `CREATE TABLE` and `ADD INDEX` (or `ADD COLUMN`) operations are completed, it will become the `public` state, indicating that the newly created table, column, and index can be read and written normally. + +- `SCHEMA_ID`: The ID of the database where the DDL operation is performed. +- `TABLE_ID`: The ID of the table where the DDL operation is performed. +- `ROW_COUNT`: When performing the `ADD INDEX` operation, it is the number of data rows that have been added. +- `START_TIME`: The start time of the DDL operation. +- `STATE`: The state of the DDL operation. Common states include the following: + + - `queueing`: indicates that the operation job has entered the DDL job queue but has not been executed because it is still waiting for the previous DDL job to complete. Another reason might be that after executing the `DROP` operation, it will become the `none` state, but it will soon be updated to the `synced` state, indicating that all TiDB instances have been synchronized to that state. + - `running`: indicates that the operation is being executed. + - `synced`: indicates that the operation has been executed successfully and all TiDB instances have been synchronized to this state. + - `rollback done`: indicates that the operation has failed and the rollback has been completed. + - `rollingback`: indicates that the operation has failed and is rolling back. + - `cancelling`: indicates that the operation is being canceled. This state only appears when using the `ADMIN CANCEL DDL JOBS` command to cancel the DDL job. + +The following example shows the results of `ADMIN SHOW DDL JOBS`: {{< copyable "sql" >}} @@ -124,17 +149,17 @@ You can only search the running DDL job corresponding to `job_id` within the las ADMIN SHOW DDL JOB QUERIES LIMIT n, m; # Retrieve rows [n+1, n+m] ADMIN SHOW DDL JOB QUERIES LIMIT m OFFSET n; # Retrieve rows [n+1, n+m] ``` - + where `n` and `m` are integers greater or equal to 0. ```sql ADMIN SHOW DDL JOB QUERIES LIMIT 3; # Retrieve first 3 rows +--------+--------------------------------------------------------------+ - | JOB_ID | QUERY | + | JOB_ID | QUERY | +--------+--------------------------------------------------------------+ - | 59 | ALTER TABLE t1 ADD INDEX index2 (col2) | - | 60 | ALTER TABLE t2 ADD INDEX index1 (col1) | - | 58 | CREATE TABLE t2 (id INT NOT NULL PRIMARY KEY auto_increment) | + | 59 | ALTER TABLE t1 ADD INDEX index2 (col2) | + | 60 | ALTER TABLE t2 ADD INDEX index1 (col1) | + | 58 | CREATE TABLE t2 (id INT NOT NULL PRIMARY KEY auto_increment) | +--------+--------------------------------------------------------------+ 3 rows in set (0.00 sec) ``` @@ -142,10 +167,10 @@ You can only search the running DDL job corresponding to `job_id` within the las ```sql ADMIN SHOW DDL JOB QUERIES LIMIT 6, 2; # Retrieve rows 7-8 +--------+----------------------------------------------------------------------------+ - | JOB_ID | QUERY | + | JOB_ID | QUERY | +--------+----------------------------------------------------------------------------+ - | 52 | ALTER TABLE t1 ADD INDEX index1 (col1) | - | 51 | CREATE TABLE IF NOT EXISTS t1 (id INT NOT NULL PRIMARY KEY auto_increment) | + | 52 | ALTER TABLE t1 ADD INDEX index1 (col1) | + | 51 | CREATE TABLE IF NOT EXISTS t1 (id INT NOT NULL PRIMARY KEY auto_increment) | +--------+----------------------------------------------------------------------------+ 3 rows in set (0.00 sec) ``` @@ -153,11 +178,11 @@ You can only search the running DDL job corresponding to `job_id` within the las ```sql ADMIN SHOW DDL JOB QUERIES LIMIT 3 OFFSET 4; # Retrieve rows 5-7 +--------+----------------------------------------+ - | JOB_ID | QUERY | + | JOB_ID | QUERY | +--------+----------------------------------------+ | 54 | DROP TABLE IF EXISTS t3 | | 53 | ALTER TABLE t1 DROP INDEX index1 | - | 52 | ALTER TABLE t1 ADD INDEX index1 (col1) | + | 52 | ALTER TABLE t1 ADD INDEX index1 (col1) | +--------+----------------------------------------+ 3 rows in set (0.00 sec) ``` From 92f154484c68bafac68968a624a66c40aecb791b Mon Sep 17 00:00:00 2001 From: Ran Date: Thu, 2 Mar 2023 15:33:16 +0800 Subject: [PATCH 05/13] add toc, cancel ddl, and media Signed-off-by: Ran --- TOC.md | 1 + media/ddl-owner.png | Bin 0 -> 55100 bytes .../sql-statement-admin-cancel-ddl.md | 2 ++ 3 files changed, 3 insertions(+) create mode 100644 media/ddl-owner.png diff --git a/TOC.md b/TOC.md index 7dd082f2435bc..8529e88290921 100644 --- a/TOC.md +++ b/TOC.md @@ -285,6 +285,7 @@ - [Use Placement Rules](/configure-placement-rules.md) - [Use Load Base Split](/configure-load-base-split.md) - [Use Store Limit](/configure-store-limit.md) + - [DDL Execution Principles and Best Practices](/ddl-introduction.md) - TiDB Tools - [Overview](/ecosystem-tool-user-guide.md) - [Use Cases](/ecosystem-tool-user-case.md) diff --git a/media/ddl-owner.png b/media/ddl-owner.png new file mode 100644 index 0000000000000000000000000000000000000000..b2524329b9ee13dfc7eea588c9e07b2cb38b70b1 GIT binary patch literal 55100 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 literal 0 HcmV?d00001 diff --git a/sql-statements/sql-statement-admin-cancel-ddl.md b/sql-statements/sql-statement-admin-cancel-ddl.md index 375883115c132..fe95d83092080 100644 --- a/sql-statements/sql-statement-admin-cancel-ddl.md +++ b/sql-statements/sql-statement-admin-cancel-ddl.md @@ -8,6 +8,8 @@ category: reference The `ADMIN CANCEL DDL` statement allows you to cancel a running DDL job. The `job_id` can be found by running [`ADMIN SHOW DDL JOBS`](/sql-statements/sql-statement-admin-show-ddl.md). +The `ADMIN CANCEL DDL` statement also allows you to cancel a DDL job that is committed but not yet completed executing. After the cancellation, the SQL statement that executes the DDL job returns the `ERROR 8214 (HY000): Cancelled DDL job` error. If you cancel a DDL job that has already been completed, you will see the `DDL Job:90 not found` error in the `RESULT` column, which indicates that the job has been removed from the DDL waiting queue. + ## Synopsis ```ebnf+diagram From 75e5fcf91bf57f705646c72d76fe395ea9b01a09 Mon Sep 17 00:00:00 2001 From: Ran Date: Thu, 2 Mar 2023 17:58:35 +0800 Subject: [PATCH 06/13] Apply suggestions from code review Co-authored-by: xixirangrang --- faq/sql-faq.md | 22 +++++++++------- .../sql-statement-admin-show-ddl.md | 26 +++++++++---------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/faq/sql-faq.md b/faq/sql-faq.md index c0eb3ba9f4ca8..2716880bc9339 100644 --- a/faq/sql-faq.md +++ b/faq/sql-faq.md @@ -239,11 +239,11 @@ SELECT column_name FROM table_name USE INDEX(index_name)WHERE where_conditio ## DDL Execution -This section lists issues related to DDL statement execution. For detailed explanations on the DDL execution principle, refer to [Execution Principles and Best Practices of DDL Statements](/ddl-introduction.md). +This section lists issues related to DDL statement execution. For detailed explanations on the DDL execution principles, see [Execution Principles and Best Practices of DDL Statements](/ddl-introduction.md). ### How long does it take to perform various DDL operations? -Assuming that DDL operations are not blocked, each TiDB server can update the schema version normally, and the DDL owner node is running normally. In this case, the estimated time for various DDL operations is as follows: +Assume that DDL operations are not blocked, each TiDB server can update the schema version normally, and the DDL Owner node is running normally. In this case, the estimated time for various DDL operations is as follows: | DDL Operation Type | Estimated Time | |:----------|:-----------| @@ -252,18 +252,18 @@ Assuming that DDL operations are not blocked, each TiDB server can update the sc > **Note:** > -> The above are estimated times for the operations. The actual time might be different. +> The above is estimated time for the operations. The actual time might be different. ### Possible reasons why DDL execution is slow -- In a user session, if there is a non-auto-commit DML statement before a DDL statement, and if the commit operation of the DML statement is slow, it will cause the DDL statement to execute slowly. That is, TiDB commits the uncommitted DML statement before executing the DDL statement. +- In a user session, if there is a non-auto-commit DML statement before a DDL statement, and if the commit operation of the non-auto-commit DML statement is slow, it will cause the DDL statement to execute slowly. That is, TiDB commits the uncommitted DML statement before executing the DDL statement. - When multiple DDL statements are executed together, the execution of the later DDL statements might be slower because they might need to wait in queue. Queuing scenarios include: - - The same type of DDL statements need to be queued. For example, both `CREATE TABLE` and `CREATE DATABASE` are general DDL statements, so when both operations are executed at the same time, they need to be queued. Since TiDB v6.2.0, parallel DDL statements are supported, but to avoid DDL execution using too many TiDB computing resources, there is also concurrency limit. Queuing occurs when DDL exceeds the concurrency limit. - - The DDL operations performed on the same table have a dependency relationship between. The later DDL statement needs to wait for the previous DDL operation to complete. + - The same type of DDL statements need to be queued. For example, both `CREATE TABLE` and `CREATE DATABASE` are general DDL statements, so when both operations are executed at the same time, they need to be queued. Starting from TiDB v6.2.0, parallel DDL statements are supported, but to avoid DDL execution using too many TiDB computing resources, there is also a concurrency limit. Queuing occurs when DDL exceeds the concurrency limit. + - The DDL operations performed on the same table have a dependency relationship between them. The later DDL statement needs to wait for the previous DDL operation to complete. -- After the cluster is started normally, the execution time of the first DDL operation might be relatively long because the DDL module is electing the DDL owner. +- After the cluster is started normally, the execution time of the first DDL operation might be relatively long because the DDL module is electing the DDL Owner. - TiDB is terminated, which causes TiDB to not able to communicate with PD normally (including power-off situations). Or TiDB is terminated by the `kill -9` command, which causes TiDB to not timely clear the registration data from PD. @@ -271,7 +271,9 @@ Assuming that DDL operations are not blocked, each TiDB server can update the sc ### What triggers the `Information schema is changed` error? -When executing SQL statements, TiDB determines the schema version of an object based on the isolation level and processes the SQL statement accordingly. TiDB also supports online asynchronous DDL changes. When executing DML statements, there may be DDL statements being executed at the same time, and you need to ensure that each SQL statement is executed on the same schema. Therefore, when executing DML, if a DDL operation is ongoing, TiDB might report an `Information schema is changed` error. Starting from v6.4.0, TiDB has implemented a [metadata lock mechanism](/metadata-lock.md), which allows the coordinated execution of DML statements and DDL schema changes, avoiding most `Information schema is changed` errors. +When executing SQL statements, TiDB determines the schema version of an object based on the isolation level and processes the SQL statement accordingly. TiDB also supports online asynchronous DDL changes. When you execute DML statements, there might be DDL statements being executed at the same time, and you need to ensure that each SQL statement is executed on the same schema. Therefore, when executing DML, if a DDL operation is ongoing, TiDB might report an `Information schema is changed` error. + +Starting from v6.4.0, TiDB has implemented a [metadata lock mechanism](/metadata-lock.md), which allows the coordinated execution of DML statements and DDL schema changes, and avoids most `Information schema is changed` errors. Now, there are still a few causes for this error reporting: @@ -311,7 +313,7 @@ For example, consider the following DDL statements: - DDL 2: `ALTER TABLE t ADD COLUMN b int;` - DDL 3: `CREATE TABLE t1(a int);` -Due to the limitation of the first-in-first-out queue, DDL 3 must wait for DDL 2 to execute. Also, because DDL statements on the same table need to be executed in serial, DDL 2 must for DDL 1 to execute. Therefore, DDL 3 needs to wait for DDL 1 to be executed first, even if they operate on different tables. +Due to the limitation of the first-in-first-out queue, DDL 3 must wait for DDL 2 to execute. Also, because DDL statements on the same table need to be executed in serial, DDL 2 must wait for DDL 1 to execute. Therefore, DDL 3 needs to wait for DDL 1 to be executed first, even if they operate on different tables. Starting from TiDB v6.2.0, the TiDB DDL module uses a concurrent framework. In the concurrent framework, there is no longer the limitation of the first-in-first-out queue. Instead, TiDB picks up the DDL task that can be executed from all DDL tasks. Additionally, the number of Reorg workers has been expanded, approximately to `CPU/4` per node. This allows TiDB to build indexes for multiple tables simultaneously in the concurrent framework. @@ -320,7 +322,7 @@ Whether your cluster is a new cluster or an upgraded cluster from an earlier ver ### Identify the cause of stuck DDL execution 1. Eliminate other reasons that make the DDL statement execution slow. -2. Use one of the following methods to identify the DDL owner node: +2. Use one of the following methods to identify the DDL Owner node: - Use `curl http://{TiDBIP}:10080/info/all` to obtain the owner of the current cluster. - View the owner during a specific time period from the monitoring dashboard **DDL** > **DDL META OPM**. diff --git a/sql-statements/sql-statement-admin-show-ddl.md b/sql-statements/sql-statement-admin-show-ddl.md index a451d55f62856..1e11e0cf80483 100644 --- a/sql-statements/sql-statement-admin-show-ddl.md +++ b/sql-statements/sql-statement-admin-show-ddl.md @@ -46,28 +46,28 @@ mysql> ADMIN SHOW DDL; The `ADMIN SHOW DDL JOBS` statement is used to view all the results in the current DDL job queue, including running and queuing tasks, as well as the latest ten results in the completed DDL job queue. The returned result fields are described as follows: -- `JOB_ID`: Each DDL operation corresponds to a DDL job. `JOB_ID` is globally unique. -- `DB_NAME`: The name of the database where the DDL operation is performed. -- `TABLE_NAME`: The name of the table where the DDL operation is performed. -- `JOB_TYPE`: The type of DDL operation. -- `SCHEMA_STATE`: The current state of the schema object that the DDL operates on. If `JOB_TYPE` is `ADD INDEX`, it is the state of the index; if `JOB_TYPE` is `ADD COLUMN`, it is the state of the column; if `JOB_TYPE` is `CREATE TABLE`, it is the state of the table. Common states include the following: +- `JOB_ID`: each DDL operation corresponds to a DDL job. `JOB_ID` is globally unique. +- `DB_NAME`: the name of the database where the DDL operation is performed. +- `TABLE_NAME`: the name of the table where the DDL operation is performed. +- `JOB_TYPE`: the type of DDL operation. +- `SCHEMA_STATE`: the current state of the schema object that the DDL operates on. If `JOB_TYPE` is `ADD INDEX`, it is the state of the index; if `JOB_TYPE` is `ADD COLUMN`, it is the state of the column; if `JOB_TYPE` is `CREATE TABLE`, it is the state of the table. Common states include the following: - `none`: indicates that it does not exist. Generally, after the `DROP` operation or after the `CREATE` operation fails and rolls back, it will become the `none` state. - - `delete only`, `write only`, `delete reorganization`, `write reorganization`: These four states are intermediate states. For their specific meanings, refer to [How the Online DDL Asynchronous Change Works in TiDB](/ddl-introduction.md#how-the-online-ddl-asynchronous-change-works-in-tidb). As the intermediate state conversion is fast, these states are generally not visible during operation. Only when performing `ADD INDEX` operation can the `write reorganization` state be seen, indicating that index data is being added. + - `delete only`, `write only`, `delete reorganization`, `write reorganization`: these four states are intermediate states. For their specific meanings, see [How the Online DDL Asynchronous Change Works in TiDB](/ddl-introduction.md#how-the-online-ddl-asynchronous-change-works-in-tidb). As the intermediate state conversion is fast, these states are generally not visible during operation. Only when performing `ADD INDEX` operation can the `write reorganization` state be seen, indicating that index data is being added. - `public`: indicates that it exists and is available to users. Generally, after `CREATE TABLE` and `ADD INDEX` (or `ADD COLUMN`) operations are completed, it will become the `public` state, indicating that the newly created table, column, and index can be read and written normally. -- `SCHEMA_ID`: The ID of the database where the DDL operation is performed. -- `TABLE_ID`: The ID of the table where the DDL operation is performed. -- `ROW_COUNT`: When performing the `ADD INDEX` operation, it is the number of data rows that have been added. -- `START_TIME`: The start time of the DDL operation. -- `STATE`: The state of the DDL operation. Common states include the following: +- `SCHEMA_ID`: the ID of the database where the DDL operation is performed. +- `TABLE_ID`: the ID of the table where the DDL operation is performed. +- `ROW_COUNT`: when performing the `ADD INDEX` operation, it is the number of data rows that have been added. +- `START_TIME`: the start time of the DDL operation. +- `STATE`: the state of the DDL operation. Common states include the following: - - `queueing`: indicates that the operation job has entered the DDL job queue but has not been executed because it is still waiting for the previous DDL job to complete. Another reason might be that after executing the `DROP` operation, it will become the `none` state, but it will soon be updated to the `synced` state, indicating that all TiDB instances have been synchronized to that state. + - `queueing`: indicates that the operation job has entered the DDL job queue but has not been executed because it is still waiting for an earlier DDL job to complete. Another reason might be that after executing the `DROP` operation, it will become the `none` state, but it will soon be updated to the `synced` state, indicating that all TiDB instances have been synchronized to that state. - `running`: indicates that the operation is being executed. - `synced`: indicates that the operation has been executed successfully and all TiDB instances have been synchronized to this state. - `rollback done`: indicates that the operation has failed and the rollback has been completed. - `rollingback`: indicates that the operation has failed and is rolling back. - - `cancelling`: indicates that the operation is being canceled. This state only appears when using the `ADMIN CANCEL DDL JOBS` command to cancel the DDL job. + - `cancelling`: indicates that the operation is being canceled. This state only appears when you use the `ADMIN CANCEL DDL JOBS` command to cancel the DDL job. The following example shows the results of `ADMIN SHOW DDL JOBS`: From 98bbc2adc5c46869f9665ada8009a54febf1660a Mon Sep 17 00:00:00 2001 From: Ran Date: Thu, 2 Mar 2023 18:21:26 +0800 Subject: [PATCH 07/13] Apply suggestions from code review Co-authored-by: xixirangrang --- ddl-introduction.md | 48 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/ddl-introduction.md b/ddl-introduction.md index 0562ada2ce1a1..d8fd0311e8bda 100644 --- a/ddl-introduction.md +++ b/ddl-introduction.md @@ -5,15 +5,15 @@ summary: Learn about how DDL statements are implemented in TiDB, the online chan # Execution Principles and Best Practices of DDL Statements -This document provides an overview of the execution principles and best practices related to DDL statements in TiDB. The topics covered include the DDL Owner module and the online DDL change process. +This document provides an overview of the execution principles and best practices related to DDL statements in TiDB. The principles include the DDL Owner module and the online DDL change process. ## DDL execution principles -TiDB uses an online and asynchronous approach to executing DDL statements. This means that DML statements in other sessions are not blocked while DDL statements are being executed. In other words, you can change the definition of database objects using online and asynchronous DDL statements while your applications are running. +TiDB uses an online and asynchronous approach to execute DDL statements. This means that DML statements in other sessions are not blocked while DDL statements are being executed. In other words, you can change the definitions of database objects using online and asynchronous DDL statements while your applications are running. ### Types of DDL statements -Based on whether a DDL statement blocks the user application during execution, DDL statements can be divided into the following types: +Based on whether DDL statements block the user application during execution, DDL statements can be divided into the following types: - **Offline DDL statements**: When the database receives a DDL statement from the user, it first locks the database object to be modified, executes the metadata change, and blocks the user application from modifying data during the DDL execution. @@ -21,25 +21,25 @@ Based on whether a DDL statement blocks the user application during execution, D Based on whether to operate the data included in the target DDL object, DDL statements can be divided into the following types: -- **Logical DDL statements**: This type of DDL statements usually only modify the metadata of the database object, without processing the data stored in the object. For example, changing the table name or changing the column name. +- **Logical DDL statements**: Logical DDL statements usually only modify the metadata of the database object, without processing the data stored in the object, for example, changing the table name or changing the column name. - In TiDB, logical DDL statements are also referred to as "general DDL". These statements typically have a short execution time, often taking only a few tens of milliseconds or seconds to complete. As a result, they do not consume much system resource and do not affect the load on the application. + In TiDB, logical DDL statements are also referred to as "general DDL". These statements typically have a short execution time, often taking only a few tens of milliseconds or seconds to complete. As a result, they do not consume much system resource and do not affect the workload on the application. -- **Physical DDL statements**: This type of DDL statements not only modifies the metadata of the object to be changed, but also modifies the user data stored in the object. For example, when TiDB creates an index for a table, it not only changes the definition of the table, but also performs a full table scan to build the newly added index. +- **Physical DDL statements**: Physical DDL statements not only modify the metadata of the object to be changed, but also modify the user data stored in the object. For example, when TiDB creates an index for a table, it not only changes the definition of the table, but also performs a full table scan to build the newly added index. - In TiDB, physical DDL statements are also referred to as "reorg DDL", which stands for reorganization. Currently, physical DDL statements only include `ADD INDEX` and lossy column type changes (such as changing from an `INT` type to a `CHAR` type). These statements take a long time to execute, and the execution time is influenced by the amount of data in the table, the machine configuration, and the application load. + In TiDB, physical DDL statements are also referred to as "reorg DDL", which stands for reorganization. Currently, physical DDL statements only include `ADD INDEX` and lossy column type changes (such as changing from an `INT` type to a `CHAR` type). These statements take a long time to execute, and the execution time is affected by the amount of data in the table, the machine configuration, and the application workload. - Executing physical DDL statements can have an impact on the load of the application for two reasons. On the one hand, it requires CPU and I/O resources from TiKV to read data and write new data. On the other hand, the TiDB node where the DDL Owner is located needs to perform the corresponding computations, which consumes more CPU resources. Because TiDB does not currently support distributed execution of DDL statements, other TiDB nodes do not consume additional system resources during this process. + Executing physical DDL statements can have an impact on the workload of the application for two reasons. On the one hand, it consumes CPU and I/O resources from TiKV to read data and write new data. On the other hand, the TiDB node where the DDL Owner is located needs to perform the corresponding computations, which consumes more CPU resources. Because TiDB does not support distributed execution of DDL statements, other TiDB nodes do not consume additional system resources during this process. > **Note:** > - > The execution of physical DDL tasks is typically what causes the greatest impact on the user application. Therefore, to minimize this impact, the focus is on optimizing the design of physical DDL statements during execution. This helps to reduce the impact on the user application. + > The execution of a physical DDL task typically causes the greatest impact on the user application. Therefore, to minimize this impact, the key point is to optimize the design of physical DDL statements during execution. This helps to reduce the impact on the user application. ### TiDB DDL module The TiDB DDL module incorporates the role of the DDL Owner (or Owner), which serves as a proxy for executing all DDL statements within the TiDB cluster. In the current implementation, only one TiDB node in the entire cluster can be elected as the Owner at any given time. Once elected, the worker started in that TiDB node can handle the DDL tasks in the cluster. -TiDB uses the election mechanism of etcd to elect a node to host the Owner from multiple TiDB nodes. By default, each TiDB node can potentially be elected as the Owner (you can configure `run-ddl` to manage node participation in the election). The elected Owner node has a term, which it actively maintains by renewing the term. When the Owner node is down, another node can be re-elected as the new Owner through etcd and continue executing DDL tasks in the cluster. +TiDB uses the election mechanism of etcd to elect a node to host the Owner from multiple TiDB nodes. By default, each TiDB node can potentially be elected as the Owner (you can configure `run-ddl` to manage node participation in the election). The elected Owner node has a term, and it actively maintains the term by renewing it. When the Owner node is down, another node can be elected as the new Owner through etcd and continue executing DDL tasks in the cluster. A simple illustration of the DDL Owner is as follows: @@ -60,9 +60,9 @@ ADMIN SHOW DDL; 1 row in set (0.00 sec) ``` -### How the Online DDL Asynchronous Change Works in TiDB +### How the online DDL asynchronous change works in TiDB -From the beginning of its design, the TiDB DDL module has opted for an online asynchronous change mode, which enables users to modify their applications without experiencing any downtime. +From the beginning of its design, the TiDB DDL module has opted for an online asynchronous change mode, which lets you modify your applications without experiencing any downtime. DDL changes involve transitioning from one state to another, typically from a "before change" state to an "after change" state. With online DDL changes, this transition occurs by introducing multiple small version states that are mutually compatible. During the execution of a DDL statement, TiDB nodes in the same cluster are allowed to have different small version changes, as long as the difference between the small versions of the change objects is not more than two versions. This is possible because adjacent small versions can be mutually compatible. @@ -77,7 +77,7 @@ absent -> delete only -> write only -> write reorg -> public For users, the newly created index is unavailable before the `public` state. -
+
Before v6.2.0, the process of handling asynchronous schema changes in the TiDB SQL layer is as follows: @@ -85,28 +85,28 @@ Before v6.2.0, the process of handling asynchronous schema changes in the TiDB S 2. After receiving the request, a TiDB server parses and optimizes the request at the MySQL Protocol layer, and then sends it to the TiDB SQL layer for execution. - Once the SQL layer of TiDB receives the DDL request, it starts the `start job` module to encapsulate the request into a specific DDL Job (that is, a DDL task), and then stores this Job in the corresponding DDL Job queue in the KV layer based on the statement type. The corresponding worker is notified of the Job that requires processing. + Once the SQL layer of TiDB receives the DDL request, it starts the `start job` module to encapsulate the request into a specific DDL job (that is, a DDL task), and then stores this job in the corresponding DDL job queue in the KV layer based on the statement type. The corresponding worker is notified of the job that requires processing. -3. When receiving the notification to process the Job, the worker determines whether it is the role of the DDL Owner. If it is the Owner role, it directly processes the Job. Otherwise, it exits without performing any processing. +3. When receiving the notification to process the job, the worker determines whether it has the role of the DDL Owner. If it does, it directly processes the job. Otherwise, it exits without any processing. - If a TiDB server is not the Owner role, then another node must be the Owner. The worker of the node in the Owner role periodically checks whether there is an available Job that can be executed. If such a Job is identified, the worker will process the Job. + If a TiDB server is not the Owner role, then another node must be the Owner. The worker of the node in the Owner role periodically checks whether there is an available job that can be executed. If such a job is identified, the worker will process the job. -4. After the worker processes the Job, it removes the Job from the Job queue in the KV layer and places it in the `job history queue`. The `start job` module that encapsulated the Job will periodically check the ID of the Job in the `job history queue` to see whether it has been processed. If so, the entire DDL operation corresponding to the Job ends. +4. After the worker processes the Job, it removes the job from the job queue in the KV layer and places it in the `job history queue`. The `start job` module that encapsulated the job periodically checks the ID of the job in the `job history queue` to see whether it has been processed. If so, the entire DDL operation corresponding to the job ends. 5. TiDB server returns the DDL processing result to the MySQL Client. Before TiDB v6.2.0, the DDL execution framework had the following limitations: - The TiKV cluster only has two queues: `general job queue` and `add index job queue`, which handle logical DDL and physical DDL, respectively. -- The DDL Owner always processes DDL Jobs in a first-in-first-out way. +- The DDL Owner always processes DDL jobs in a first-in-first-out way. - The DDL Owner can only execute one DDL task of the same type (logical or physical) at a time, which is relatively strict. These limitations might lead to some "unintended" DDL blocking behavior. For more details, see [SQL FAQ - DDL Execution](/faq/sql-faq.md#ddl-execution).
-
+
-Before TiDB v6.2, because the Owner can only execute one DDL task of the same type (logical or physical) at a time, which is relatively strict, and affects the user experience. +Before TiDB v6.2.0, because the Owner can only execute one DDL task of the same type (either logical or physical) at a time, which is relatively strict, and affects the user experience. If there is no dependency between DDL tasks, parallel execution does not affect data correctness and consistency. For example, user A adds an index to the `T1` table, while user B deletes a column from the `T2` table. These two DDL statements can be executed in parallel. @@ -121,10 +121,10 @@ To improve the user experience of DDL execution, starting from v6.2.0, TiDB enab In specific, TiDB has upgraded the DDL execution framework in v6.2.0 in the following aspects: + The DDL Owner can execute DDL tasks in parallel based on the preceding logic. -+ The first-in-first-out issue in the DDL Job queue has been addressed. The DDL Owner no longer selects the first Job in the queue, but instead selects the Job that can be executed at the current time. -+ The number of workers that handle physical DDL has been increased, enabling multiple physical DDLs to be executed in parallel. ++ The first-in-first-out issue in the DDL Job queue has been addressed. The DDL Owner no longer selects the first job in the queue, but instead selects the job that can be executed at the current time. ++ The number of workers that handle physical DDL statements has been increased, enabling multiple physical DDL statements to be executed in parallel. - Because all DDL tasks in TiDB are implemented using an online change approach, TiDB can determine the relevance of new DDL Jobs through the Owner, and schedule DDL tasks based on this information. This approach enables the distributed database to achieve the same level of DDL concurrency as traditional databases. + Because all DDL tasks in TiDB are implemented using an online change approach, TiDB can determine the relevance of new DDL jobs through the Owner, and schedule DDL tasks based on this information. This approach enables the distributed database to achieve the same level of DDL concurrency as traditional databases. The concurrent DDL framework enhances the execution capability of DDL statements in TiDB, making it more compatible with the usage patterns of commercial databases. @@ -135,7 +135,7 @@ The concurrent DDL framework enhances the execution capability of DDL statements ### Balance the physical DDL execution speed and the impact on application load through system variables -When executing physical DDLs (including adding indexes or column type changes), you can adjust the values of the following system variables to balance the speed of DDL execution and the impact on application load: +When executing physical DDL statements (including adding indexes or column type changes), you can adjust the values of the following system variables to balance the speed of DDL execution and the impact on application load: - [`tidb_ddl_reorg_worker_cnt`](/system-variables.md#tidb_ddl_reorg_worker_cnt): This variable sets the number of reorg workers for a DDL operation, which controls the concurrency of backfilling. From 4d66a6cb678b6ed29f7d29981ae2f1863db6c9ae Mon Sep 17 00:00:00 2001 From: xixirangrang Date: Thu, 2 Mar 2023 18:56:45 +0800 Subject: [PATCH 08/13] Update ddl-introduction.md Co-authored-by: Ran --- ddl-introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddl-introduction.md b/ddl-introduction.md index d8fd0311e8bda..a62e18d1a6e5f 100644 --- a/ddl-introduction.md +++ b/ddl-introduction.md @@ -15,7 +15,7 @@ TiDB uses an online and asynchronous approach to execute DDL statements. This me Based on whether DDL statements block the user application during execution, DDL statements can be divided into the following types: -- **Offline DDL statements**: When the database receives a DDL statement from the user, it first locks the database object to be modified, executes the metadata change, and blocks the user application from modifying data during the DDL execution. +- **Offline DDL statements**: When the database receives a DDL statement from the user, it first locks the database object to be modified and then changes the metadata. During the DDL execution, the database blocks the user application from modifying data. - **Online DDL statements**: When a DDL statement is executed in the database, a specific method is used to ensure that the statement does not block the user application. This allows the user to submit modifications during the DDL execution. The method also ensures the correctness and consistency of the corresponding database object during the execution process. From 363dd120e325c1867ba728cc2a3eedb296cbc038 Mon Sep 17 00:00:00 2001 From: xixirangrang Date: Thu, 2 Mar 2023 19:05:02 +0800 Subject: [PATCH 09/13] Apply suggestions from code review --- ddl-introduction.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ddl-introduction.md b/ddl-introduction.md index a62e18d1a6e5f..ae5501ea66be1 100644 --- a/ddl-introduction.md +++ b/ddl-introduction.md @@ -37,7 +37,7 @@ Based on whether to operate the data included in the target DDL object, DDL stat ### TiDB DDL module -The TiDB DDL module incorporates the role of the DDL Owner (or Owner), which serves as a proxy for executing all DDL statements within the TiDB cluster. In the current implementation, only one TiDB node in the entire cluster can be elected as the Owner at any given time. Once elected, the worker started in that TiDB node can handle the DDL tasks in the cluster. +The TiDB DDL module introduces the role of the DDL Owner (or Owner), which serves as a proxy for executing all DDL statements within the TiDB cluster. In the current implementation, only one TiDB node in the entire cluster can be elected as the Owner at any given time. Once a TiDB node is elected as Owner, the worker started in that TiDB node can handle the DDL tasks in the cluster. TiDB uses the election mechanism of etcd to elect a node to host the Owner from multiple TiDB nodes. By default, each TiDB node can potentially be elected as the Owner (you can configure `run-ddl` to manage node participation in the election). The elected Owner node has a term, and it actively maintains the term by renewing it. When the Owner node is down, another node can be elected as the new Owner through etcd and continue executing DDL tasks in the cluster. @@ -81,7 +81,7 @@ For users, the newly created index is unavailable before the `public` state. Before v6.2.0, the process of handling asynchronous schema changes in the TiDB SQL layer is as follows: -1. MySQL Client sends a DDL request to the TiDB server. +1. MySQL Client sends a DDL request to a TiDB server. 2. After receiving the request, a TiDB server parses and optimizes the request at the MySQL Protocol layer, and then sends it to the TiDB SQL layer for execution. @@ -99,7 +99,7 @@ Before TiDB v6.2.0, the DDL execution framework had the following limitations: - The TiKV cluster only has two queues: `general job queue` and `add index job queue`, which handle logical DDL and physical DDL, respectively. - The DDL Owner always processes DDL jobs in a first-in-first-out way. -- The DDL Owner can only execute one DDL task of the same type (logical or physical) at a time, which is relatively strict. +- The DDL Owner can only execute one DDL task of the same type (either logical or physical) at a time, which is relatively strict, and affects the user experience. These limitations might lead to some "unintended" DDL blocking behavior. For more details, see [SQL FAQ - DDL Execution](/faq/sql-faq.md#ddl-execution). From 47431241c54e705369007a5aae47f48c0f8929e2 Mon Sep 17 00:00:00 2001 From: xixirangrang <35301108+hfxsd@users.noreply.github.com> Date: Thu, 2 Mar 2023 19:15:03 +0800 Subject: [PATCH 10/13] Update tidb-troubleshooting-map.md --- tidb-troubleshooting-map.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tidb-troubleshooting-map.md b/tidb-troubleshooting-map.md index c1989d7685691..32e1c09ca6241 100644 --- a/tidb-troubleshooting-map.md +++ b/tidb-troubleshooting-map.md @@ -79,7 +79,7 @@ Refer to [5 PD issues](#5-pd-issues). - 3.1.3 TiDB reports `information schema is changed` error in log - - For the detailed causes and solution, see [Why the `Information schema is changed` error is reported](/faq/sql-faq.md#why-the-information-schema-is-changed-error-is-reported). + - For the detailed causes and solution, see [Why the `Information schema is changed` error is reported](/faq/sql-faq.md#what-triggers-the-information-schema-is-changed-error). - Background: The increased number of `schema version` is consistent with the number of `schema state` of each DDL change operation. For example, the `create table` operation has 1 version change, and the `add column` operation has 4 version changes. Therefore, too many column change operations might cause `schema version` to increase fast. For details, refer to [online schema change](https://static.googleusercontent.com/media/research.google.com/zh-CN//pubs/archive/41376.pdf). From 2f1846fef89282e0be820800673d23a4c0263c92 Mon Sep 17 00:00:00 2001 From: xixirangrang <35301108+hfxsd@users.noreply.github.com> Date: Thu, 2 Mar 2023 19:32:14 +0800 Subject: [PATCH 11/13] Update sql-statement-admin-show-ddl.md --- sql-statements/sql-statement-admin-show-ddl.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sql-statements/sql-statement-admin-show-ddl.md b/sql-statements/sql-statement-admin-show-ddl.md index 1e11e0cf80483..486cfe7c41b54 100644 --- a/sql-statements/sql-statement-admin-show-ddl.md +++ b/sql-statements/sql-statement-admin-show-ddl.md @@ -52,10 +52,22 @@ The `ADMIN SHOW DDL JOBS` statement is used to view all the results in the curre - `JOB_TYPE`: the type of DDL operation. - `SCHEMA_STATE`: the current state of the schema object that the DDL operates on. If `JOB_TYPE` is `ADD INDEX`, it is the state of the index; if `JOB_TYPE` is `ADD COLUMN`, it is the state of the column; if `JOB_TYPE` is `CREATE TABLE`, it is the state of the table. Common states include the following: + + - `none`: indicates that it does not exist. Generally, after the `DROP` operation or after the `CREATE` operation fails and rolls back, it will become the `none` state. - `delete only`, `write only`, `delete reorganization`, `write reorganization`: these four states are intermediate states. For their specific meanings, see [How the Online DDL Asynchronous Change Works in TiDB](/ddl-introduction.md#how-the-online-ddl-asynchronous-change-works-in-tidb). As the intermediate state conversion is fast, these states are generally not visible during operation. Only when performing `ADD INDEX` operation can the `write reorganization` state be seen, indicating that index data is being added. - `public`: indicates that it exists and is available to users. Generally, after `CREATE TABLE` and `ADD INDEX` (or `ADD COLUMN`) operations are completed, it will become the `public` state, indicating that the newly created table, column, and index can be read and written normally. + + + + + - `none`: indicates that it does not exist. Generally, after the `DROP` operation or after the `CREATE` operation fails and rolls back, it will become the `none` state. + - `delete only`, `write only`, `delete reorganization`, `write reorganization`: these four states are intermediate states. For their specific meanings, see [How the Online DDL Asynchronous Change Works in TiDB](https://docs.pingcap.com/tidb/stable/ddl-introduction#how-the-online-ddl-asynchronous-change-works-in-tidb). As the intermediate state conversion is fast, these states are generally not visible during operation. Only when performing `ADD INDEX` operation can the `write reorganization` state be seen, indicating that index data is being added. + - `public`: indicates that it exists and is available to users. Generally, after `CREATE TABLE` and `ADD INDEX` (or `ADD COLUMN`) operations are completed, it will become the `public` state, indicating that the newly created table, column, and index can be read and written normally. + + + - `SCHEMA_ID`: the ID of the database where the DDL operation is performed. - `TABLE_ID`: the ID of the table where the DDL operation is performed. - `ROW_COUNT`: when performing the `ADD INDEX` operation, it is the number of data rows that have been added. From 98d2110ec4a4fe7f20176166354b8cd0c065e79f Mon Sep 17 00:00:00 2001 From: xixirangrang <35301108+hfxsd@users.noreply.github.com> Date: Thu, 2 Mar 2023 19:37:53 +0800 Subject: [PATCH 12/13] Update sql-statement-admin-show-ddl.md --- .../sql-statement-admin-show-ddl.md | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/sql-statements/sql-statement-admin-show-ddl.md b/sql-statements/sql-statement-admin-show-ddl.md index 486cfe7c41b54..37f7f58820130 100644 --- a/sql-statements/sql-statement-admin-show-ddl.md +++ b/sql-statements/sql-statement-admin-show-ddl.md @@ -46,28 +46,45 @@ mysql> ADMIN SHOW DDL; The `ADMIN SHOW DDL JOBS` statement is used to view all the results in the current DDL job queue, including running and queuing tasks, as well as the latest ten results in the completed DDL job queue. The returned result fields are described as follows: + + - `JOB_ID`: each DDL operation corresponds to a DDL job. `JOB_ID` is globally unique. - `DB_NAME`: the name of the database where the DDL operation is performed. - `TABLE_NAME`: the name of the table where the DDL operation is performed. - `JOB_TYPE`: the type of DDL operation. - `SCHEMA_STATE`: the current state of the schema object that the DDL operates on. If `JOB_TYPE` is `ADD INDEX`, it is the state of the index; if `JOB_TYPE` is `ADD COLUMN`, it is the state of the column; if `JOB_TYPE` is `CREATE TABLE`, it is the state of the table. Common states include the following: - - - `none`: indicates that it does not exist. Generally, after the `DROP` operation or after the `CREATE` operation fails and rolls back, it will become the `none` state. - `delete only`, `write only`, `delete reorganization`, `write reorganization`: these four states are intermediate states. For their specific meanings, see [How the Online DDL Asynchronous Change Works in TiDB](/ddl-introduction.md#how-the-online-ddl-asynchronous-change-works-in-tidb). As the intermediate state conversion is fast, these states are generally not visible during operation. Only when performing `ADD INDEX` operation can the `write reorganization` state be seen, indicating that index data is being added. - `public`: indicates that it exists and is available to users. Generally, after `CREATE TABLE` and `ADD INDEX` (or `ADD COLUMN`) operations are completed, it will become the `public` state, indicating that the newly created table, column, and index can be read and written normally. +- `SCHEMA_ID`: the ID of the database where the DDL operation is performed. +- `TABLE_ID`: the ID of the table where the DDL operation is performed. +- `ROW_COUNT`: when performing the `ADD INDEX` operation, it is the number of data rows that have been added. +- `START_TIME`: the start time of the DDL operation. +- `STATE`: the state of the DDL operation. Common states include the following: + + - `queueing`: indicates that the operation job has entered the DDL job queue but has not been executed because it is still waiting for an earlier DDL job to complete. Another reason might be that after executing the `DROP` operation, it will become the `none` state, but it will soon be updated to the `synced` state, indicating that all TiDB instances have been synchronized to that state. + - `running`: indicates that the operation is being executed. + - `synced`: indicates that the operation has been executed successfully and all TiDB instances have been synchronized to this state. + - `rollback done`: indicates that the operation has failed and the rollback has been completed. + - `rollingback`: indicates that the operation has failed and is rolling back. + - `cancelling`: indicates that the operation is being canceled. This state only appears when you use the `ADMIN CANCEL DDL JOBS` command to cancel the DDL job. + +- `JOB_ID`: each DDL operation corresponds to a DDL job. `JOB_ID` is globally unique. +- `DB_NAME`: the name of the database where the DDL operation is performed. +- `TABLE_NAME`: the name of the table where the DDL operation is performed. +- `JOB_TYPE`: the type of DDL operation. +- `SCHEMA_STATE`: the current state of the schema object that the DDL operates on. If `JOB_TYPE` is `ADD INDEX`, it is the state of the index; if `JOB_TYPE` is `ADD COLUMN`, it is the state of the column; if `JOB_TYPE` is `CREATE TABLE`, it is the state of the table. Common states include the following: + - `none`: indicates that it does not exist. Generally, after the `DROP` operation or after the `CREATE` operation fails and rolls back, it will become the `none` state. - `delete only`, `write only`, `delete reorganization`, `write reorganization`: these four states are intermediate states. For their specific meanings, see [How the Online DDL Asynchronous Change Works in TiDB](https://docs.pingcap.com/tidb/stable/ddl-introduction#how-the-online-ddl-asynchronous-change-works-in-tidb). As the intermediate state conversion is fast, these states are generally not visible during operation. Only when performing `ADD INDEX` operation can the `write reorganization` state be seen, indicating that index data is being added. - `public`: indicates that it exists and is available to users. Generally, after `CREATE TABLE` and `ADD INDEX` (or `ADD COLUMN`) operations are completed, it will become the `public` state, indicating that the newly created table, column, and index can be read and written normally. - - - `SCHEMA_ID`: the ID of the database where the DDL operation is performed. - `TABLE_ID`: the ID of the table where the DDL operation is performed. - `ROW_COUNT`: when performing the `ADD INDEX` operation, it is the number of data rows that have been added. @@ -81,6 +98,8 @@ The `ADMIN SHOW DDL JOBS` statement is used to view all the results in the curre - `rollingback`: indicates that the operation has failed and is rolling back. - `cancelling`: indicates that the operation is being canceled. This state only appears when you use the `ADMIN CANCEL DDL JOBS` command to cancel the DDL job. + + The following example shows the results of `ADMIN SHOW DDL JOBS`: {{< copyable "sql" >}} From b159ddbbd3a9a038ead44050cfa0eff34ac84917 Mon Sep 17 00:00:00 2001 From: xixirangrang <35301108+hfxsd@users.noreply.github.com> Date: Thu, 2 Mar 2023 19:48:09 +0800 Subject: [PATCH 13/13] Update sql-statement-admin-show-ddl.md --- sql-statements/sql-statement-admin-show-ddl.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sql-statements/sql-statement-admin-show-ddl.md b/sql-statements/sql-statement-admin-show-ddl.md index 37f7f58820130..ecbad399bcac9 100644 --- a/sql-statements/sql-statement-admin-show-ddl.md +++ b/sql-statements/sql-statement-admin-show-ddl.md @@ -53,17 +53,14 @@ The `ADMIN SHOW DDL JOBS` statement is used to view all the results in the curre - `TABLE_NAME`: the name of the table where the DDL operation is performed. - `JOB_TYPE`: the type of DDL operation. - `SCHEMA_STATE`: the current state of the schema object that the DDL operates on. If `JOB_TYPE` is `ADD INDEX`, it is the state of the index; if `JOB_TYPE` is `ADD COLUMN`, it is the state of the column; if `JOB_TYPE` is `CREATE TABLE`, it is the state of the table. Common states include the following: - - `none`: indicates that it does not exist. Generally, after the `DROP` operation or after the `CREATE` operation fails and rolls back, it will become the `none` state. - `delete only`, `write only`, `delete reorganization`, `write reorganization`: these four states are intermediate states. For their specific meanings, see [How the Online DDL Asynchronous Change Works in TiDB](/ddl-introduction.md#how-the-online-ddl-asynchronous-change-works-in-tidb). As the intermediate state conversion is fast, these states are generally not visible during operation. Only when performing `ADD INDEX` operation can the `write reorganization` state be seen, indicating that index data is being added. - `public`: indicates that it exists and is available to users. Generally, after `CREATE TABLE` and `ADD INDEX` (or `ADD COLUMN`) operations are completed, it will become the `public` state, indicating that the newly created table, column, and index can be read and written normally. - - `SCHEMA_ID`: the ID of the database where the DDL operation is performed. - `TABLE_ID`: the ID of the table where the DDL operation is performed. - `ROW_COUNT`: when performing the `ADD INDEX` operation, it is the number of data rows that have been added. - `START_TIME`: the start time of the DDL operation. - `STATE`: the state of the DDL operation. Common states include the following: - - `queueing`: indicates that the operation job has entered the DDL job queue but has not been executed because it is still waiting for an earlier DDL job to complete. Another reason might be that after executing the `DROP` operation, it will become the `none` state, but it will soon be updated to the `synced` state, indicating that all TiDB instances have been synchronized to that state. - `running`: indicates that the operation is being executed. - `synced`: indicates that the operation has been executed successfully and all TiDB instances have been synchronized to this state. @@ -80,17 +77,14 @@ The `ADMIN SHOW DDL JOBS` statement is used to view all the results in the curre - `TABLE_NAME`: the name of the table where the DDL operation is performed. - `JOB_TYPE`: the type of DDL operation. - `SCHEMA_STATE`: the current state of the schema object that the DDL operates on. If `JOB_TYPE` is `ADD INDEX`, it is the state of the index; if `JOB_TYPE` is `ADD COLUMN`, it is the state of the column; if `JOB_TYPE` is `CREATE TABLE`, it is the state of the table. Common states include the following: - - `none`: indicates that it does not exist. Generally, after the `DROP` operation or after the `CREATE` operation fails and rolls back, it will become the `none` state. - `delete only`, `write only`, `delete reorganization`, `write reorganization`: these four states are intermediate states. For their specific meanings, see [How the Online DDL Asynchronous Change Works in TiDB](https://docs.pingcap.com/tidb/stable/ddl-introduction#how-the-online-ddl-asynchronous-change-works-in-tidb). As the intermediate state conversion is fast, these states are generally not visible during operation. Only when performing `ADD INDEX` operation can the `write reorganization` state be seen, indicating that index data is being added. - `public`: indicates that it exists and is available to users. Generally, after `CREATE TABLE` and `ADD INDEX` (or `ADD COLUMN`) operations are completed, it will become the `public` state, indicating that the newly created table, column, and index can be read and written normally. - - `SCHEMA_ID`: the ID of the database where the DDL operation is performed. - `TABLE_ID`: the ID of the table where the DDL operation is performed. - `ROW_COUNT`: when performing the `ADD INDEX` operation, it is the number of data rows that have been added. - `START_TIME`: the start time of the DDL operation. - `STATE`: the state of the DDL operation. Common states include the following: - - `queueing`: indicates that the operation job has entered the DDL job queue but has not been executed because it is still waiting for an earlier DDL job to complete. Another reason might be that after executing the `DROP` operation, it will become the `none` state, but it will soon be updated to the `synced` state, indicating that all TiDB instances have been synchronized to that state. - `running`: indicates that the operation is being executed. - `synced`: indicates that the operation has been executed successfully and all TiDB instances have been synchronized to this state.