From f55ec5b00d98cebb3a5ec21428a9319f4a666876 Mon Sep 17 00:00:00 2001 From: ChangRui-Ryan Date: Mon, 10 Nov 2025 12:06:28 +0800 Subject: [PATCH 01/12] Do not merge until v8.5.4: MySQL compatibility about decimal insert through jdbc (#22007) --- develop/dev-guide-sample-application-java-jdbc.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/develop/dev-guide-sample-application-java-jdbc.md b/develop/dev-guide-sample-application-java-jdbc.md index 2de789c41ac10..9e4f66f36b89f 100644 --- a/develop/dev-guide-sample-application-java-jdbc.md +++ b/develop/dev-guide-sample-application-java-jdbc.md @@ -310,6 +310,17 @@ Unless you need to write complex SQL statements, it is recommended to use [ORM]( - Reduce [boilerplate code](https://en.wikipedia.org/wiki/Boilerplate_code) for managing connections and transactions. - Manipulate data with data objects instead of a number of SQL statements. +### MySQL compatibility + +In MySQL, when you insert data into a `DECIMAL` column, if the number of decimal places exceeds the column's defined scale, MySQL automatically truncates the extra digits and inserts the truncated data successfully, regardless of how many extra decimal places there are. + +In TiDB v8.5.3 and earlier versions: + +- If the number of decimal places exceeds the defined scale but does not exceed 72, TiDB also automatically truncates the extra digits and inserts the truncated data successfully. +- However, if the number of decimal places exceeds 72, the insertion fails and returns an error. + +Starting from TiDB v8.5.4, TiDB aligns its behavior with MySQL: regardless of how many extra decimal places there are, it automatically truncates the extra digits and inserts the truncated data successfully. + ## Next steps - Learn more usage of MySQL Connector/J from [the documentation of MySQL Connector/J](https://dev.mysql.com/doc/connector-j/en/). From bc0be4373832beb1b15bbcb33c094652a5f7d4f8 Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Mon, 10 Nov 2025 13:37:13 +0800 Subject: [PATCH 02/12] Add docs for Analyze Embedded in DDL and new system variable (#22014) (#22035) --- TOC-tidb-cloud.md | 1 + TOC.md | 3 +- ddl_embedded_analyze.md | 177 ++++++++++++++++++++++++++++++++++++++++ system-variables.md | 8 ++ 4 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 ddl_embedded_analyze.md diff --git a/TOC-tidb-cloud.md b/TOC-tidb-cloud.md index 5733a733d5795..edca58a37e1f0 100644 --- a/TOC-tidb-cloud.md +++ b/TOC-tidb-cloud.md @@ -735,6 +735,7 @@ - [Table Filter](/table-filter.md) - [URI Formats of External Storage Services](/external-storage-uri.md) - [DDL Execution Principles and Best Practices](/ddl-introduction.md) + - [`ANALYZE` Embedded in DDL Statements](/ddl_embedded_analyze.md) - [Batch Processing](/batch-processing.md) - [Troubleshoot Inconsistency Between Data and Indexes](/troubleshoot-data-inconsistency-errors.md) - [Notifications](/tidb-cloud/notifications.md) diff --git a/TOC.md b/TOC.md index 2065601e434f4..8e7fb55126249 100644 --- a/TOC.md +++ b/TOC.md @@ -1078,7 +1078,8 @@ - [Schedule Replicas by Topology Labels](/schedule-replicas-by-topology-labels.md) - [URI Formats of External Storage Services](/external-storage-uri.md) - [Interaction Test on Online Workloads and `ADD INDEX` Operations](/benchmark/online-workloads-and-add-index-operations.md) -- FAQs + - [`ANALYZE` Embedded in DDL Statements](/ddl_embedded_analyze.md) + FAQs - [FAQ Summary](/faq/faq-overview.md) - [TiDB FAQs](/faq/tidb-faq.md) - [SQL FAQs](/faq/sql-faq.md) diff --git a/ddl_embedded_analyze.md b/ddl_embedded_analyze.md new file mode 100644 index 0000000000000..9de981b1c2467 --- /dev/null +++ b/ddl_embedded_analyze.md @@ -0,0 +1,177 @@ +--- +title: `ANALYZE` Embedded in DDL Statements +summary: This document describes the `ANALYZE` feature embedded in DDL statements for newly created or reorganized indexes, which ensures that statistics for new indexes are updated promptly. +--- + +# `ANALYZE` Embedded in DDL StatementsIntroduced in v8.5.4 and v9.0.0 + +This document describes the `ANALYZE` feature embedded in the following two types of DDL statements: + +- DDL statements that create new indexes: [`ADD INDEX`](/sql-statements/sql-statement-add-index.md) +- DDL statements that reorganize existing indexes: [`MODIFY COLUMN`](/sql-statements/sql-statement-modify-column.md) and [`CHANGE COLUMN`](/sql-statements/sql-statement-change-column.md) + +When this feature is enabled, TiDB automatically runs an `ANALYZE` (statistics collection) operation before the new or reorganized index becomes visible to users. This prevents inaccurate optimizer estimates and potential plan changes caused by temporarily unavailable statistics after index creation or reorganization. + +## Usage scenarios + +In scenarios where DDL operations alternately add or modify indexes, existing stable queries might suffer from estimation bias because the new index lacks statistics, causing the optimizer to choose suboptimal plans. For more information, see [Issue #57948](https://github.com/pingcap/tidb/issues/57948). + +For example: + +```sql +CREATE TABLE t (a INT, b INT); +INSERT INTO t VALUES (1, 1), (2, 2), (3, 3); +INSERT INTO t SELECT * FROM t; -- * N times + +ALTER TABLE t ADD INDEX idx_a (a); + +EXPLAIN SELECT * FROM t WHERE a > 4; +``` + +``` ++-------------------------+-----------+-----------+---------------+--------------------------------+ +| id | estRows | task | access object | operator info | ++-------------------------+-----------+-----------+---------------+--------------------------------+ +| TableReader_8 | 131072.00 | root | | data:Selection_7 | +| └─Selection_7 | 131072.00 | cop[tikv] | | gt(test.t.a, 4) | +| └─TableFullScan_6 | 393216.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | ++-------------------------+-----------+-----------+---------------+--------------------------------+ +3 rows in set (0.002 sec) +``` + +In the preceding plan, because the newly created index has no statistics yet, TiDB can only rely on heuristic rules for path estimation. Unless the index access path requires no table lookup and has a significantly lower cost, the optimizer tends to choose the more stable existing path. In the preceding example, it chooses a full table scan. However, from the data distribution perspective, `t.a > 4` actually returns 0 rows. If the new index `idx_a` were used, the query could quickly locate relevant rows and avoid the full table scan. In this example, because statistics are not promptly collected after the DDL creates the index, the generated plan is not optimal, but the optimizer continues to use the original plan so query performance does not sharply regress. However, according to [Issue #57948](https://github.com/pingcap/tidb/issues/57948), in some cases heuristics might cause an unreasonable comparison between old and new indexes, pruning the index that the original plan relies on and ultimately falling back to a full table scan. + +Starting from v8.5.0, TiDB has improved heuristic comparisons between indexes and behaviors when statistics are missing. Still, in some complex scenarios, embedding `ANALYZE` in DDL is the best way to prevent plan changes. You can control whether to run embedded `ANALYZE` during index creation or reorganization with the system variable [`tidb_stats_update_during_ddl`](/system-variables.md#tidb_stats_update_during_ddl-new-in-v854-and-v900). The default value is `OFF`. + +## `ADD INDEX` DDL + +When `tidb_stats_update_during_ddl` is `ON`, executing [`ADD INDEX`](/sql-statements/sql-statement-add-index.md) automatically runs an embedded `ANALYZE` operation after the Reorg phase finishes. This `ANALYZE` operation collects statistics for the newly created index before the index becomes visible to users, and then `ADD INDEX` proceeds with its remaining phases. + +Considering that `ANALYZE` can take time, TiDB sets a timeout threshold based on the execution time of the first Reorg. If `ANALYZE` times out, `ADD INDEX` stops waiting synchronously for `ANALYZE` to finish and continues the subsequent process, making the index visible earlier to users. This means the index statistics will be updated after `ANALYZE` completes asynchronously. + +For example: + +```sql +CREATE TABLE t (a INT, b INT, c INT); +Query OK, 0 rows affected (0.011 sec) + +INSERT INTO t VALUES (1, 1, 1), (2, 2, 2), (3, 3, 3); +Query OK, 3 rows affected (0.003 sec) +Records: 3 Duplicates: 0 Warnings: 0 + +SET @@tidb_stats_update_during_ddl = 1; +Query OK, 0 rows affected (0.001 sec) + +ALTER TABLE t ADD INDEX idx (a, b); +Query OK, 0 rows affected (0.049 sec) +``` + +```sql +EXPLAIN SELECT a FROM t WHERE a > 1; +``` + +``` ++------------------------+---------+-----------+--------------------------+----------------------------------+ +| id | estRows | task | access object | operator info | ++------------------------+---------+-----------+--------------------------+----------------------------------+ +| IndexReader_7 | 4.00 | root | | index:IndexRangeScan_6 | +| └─IndexRangeScan_6 | 4.00 | cop[tikv] | table:t, index:idx(a, b) | range:(1,+inf], keep order:false | ++------------------------+---------+-----------+--------------------------+----------------------------------+ +2 rows in set (0.002 sec) +``` + +```sql +SHOW STATS_HISTOGRAMS WHERE table_name = "t"; +``` + +``` ++---------+------------+----------------+-------------+----------+---------------------+----------------+------------+--------------+-------------+-------------+-----------------+----------------+----------------+---------------+ +| Db_name | Table_name | Partition_name | Column_name | Is_index | Update_time | Distinct_count | Null_count | Avg_col_size | Correlation | Load_status | Total_mem_usage | Hist_mem_usage | Topn_mem_usage | Cms_mem_usage | ++---------+------------+----------------+-------------+----------+---------------------+----------------+------------+--------------+-------------+-------------+-----------------+----------------+----------------+---------------+ +| test | t | | a | 0 | 2025-10-30 20:17:57 | 3 | 0 | 0.5 | 1 | allLoaded | 155 | 0 | 155 | 0 | +| test | t | | idx | 1 | 2025-10-30 20:17:57 | 3 | 0 | 0 | 0 | allLoaded | 182 | 0 | 182 | 0 | ++---------+------------+----------------+-------------+----------+---------------------+----------------+------------+--------------+-------------+-------------+-----------------+----------------+----------------+---------------+ +2 rows in set (0.013 sec) +``` + +```sql +ADMIN SHOW DDL JOBS 1; +``` + +``` ++--------+---------+--------------------------+---------------+----------------------+-----------+----------+-----------+----------------------------+----------------------------+----------------------------+---------+----------------------------------------+ +| JOB_ID | DB_NAME | TABLE_NAME | JOB_TYPE | SCHEMA_STATE | SCHEMA_ID | TABLE_ID | ROW_COUNT | CREATE_TIME | START_TIME | END_TIME | STATE | COMMENTS | ++--------+---------+--------------------------+---------------+----------------------+-----------+----------+-----------+----------------------------+----------------------------+----------------------------+---------+----------------------------------------+ +| 151 | test | t | add index | write reorganization | 2 | 148 | 6291456 | 2025-10-29 00:14:47.181000 | 2025-10-29 00:14:47.183000 | NULL | running | analyzing, txn-merge, max_node_count=3 | ++--------+---------+--------------------------+---------------+----------------------+-----------+----------+-----------+----------------------------+----------------------------+----------------------------+---------+----------------------------------------+ +1 rows in set (0.001 sec) +``` + +From the `ADD INDEX` example, when `tidb_stats_update_during_ddl` is `ON`, you can see that after the execution of the `ADD INDEX` DDL statement, the subsequent `EXPLAIN` output shows that statistics for the index `idx` have been automatically collected and loaded into memory (you can verify it by executing `SHOW STATS_HISTOGRAMS`). As a result, the optimizer can immediately use these statistics for range scans. If index creation or reorganization and `ANALYZE` take a long time, you can check the DDL job status by executing `ADMIN SHOW DDL JOBS`. When the `COMMENTS` column in the output contains `analyzing`, it means that the DDL job is collecting statistics. + +## DDL for reorganizing existing indexes + +When `tidb_stats_update_during_ddl` is `ON`, executing [`MODIFY COLUMN`](/sql-statements/sql-statement-modify-column.md) or [`CHANGE COLUMN`](/sql-statements/sql-statement-change-column.md) that reorganizes an index will also run an embedded `ANALYZE` operation after the Reorg phase completes. The mechanism is the same as for `ADD INDEX`: + +- Start collecting statistics before the index becomes visible. +- If `ANALYZE` times out, [`MODIFY COLUMN`](/sql-statements/sql-statement-modify-column.md) and [`CHANGE COLUMN`](/sql-statements/sql-statement-change-column.md) stops waiting synchronously for `ANALYZE` to finish and continues the subsequent process, making the index visible earlier to users. This means that the index statistics will be updated when `ANALYZE` finishes asynchronously. + +For example: + +```sql +CREATE TABLE s (a VARCHAR(10), INDEX idx (a)); +Query OK, 0 rows affected (0.012 sec) + +INSERT INTO s VALUES (1), (2), (3); +Query OK, 3 rows affected (0.003 sec) +Records: 3 Duplicates: 0 Warnings: 0 + +SET @@tidb_stats_update_during_ddl = 1; +Query OK, 0 rows affected (0.001 sec) + +ALTER TABLE s MODIFY COLUMN a INT; +Query OK, 0 rows affected (0.056 sec) + +EXPLAIN SELECT * FROM s WHERE a > 1; +``` + +``` ++------------------------+---------+-----------+-----------------------+----------------------------------+ +| id | estRows | task | access object | operator info | ++------------------------+---------+-----------+-----------------------+----------------------------------+ +| IndexReader_7 | 2.00 | root | | index:IndexRangeScan_6 | +| └─IndexRangeScan_6 | 2.00 | cop[tikv] | table:s, index:idx(a) | range:(1,+inf], keep order:false | ++------------------------+---------+-----------+-----------------------+----------------------------------+ +2 rows in set (0.005 sec) +``` + +```sql +SHOW STATS_HISTOGRAMS WHERE table_name = "s"; +``` + +``` ++---------+------------+----------------+-------------+----------+---------------------+----------------+------------+--------------+-------------+-------------+-----------------+----------------+----------------+---------------+ +| Db_name | Table_name | Partition_name | Column_name | Is_index | Update_time | Distinct_count | Null_count | Avg_col_size | Correlation | Load_status | Total_mem_usage | Hist_mem_usage | Topn_mem_usage | Cms_mem_usage | ++---------+------------+----------------+-------------+----------+---------------------+----------------+------------+--------------+-------------+-------------+-----------------+----------------+----------------+---------------+ +| test | s | | a | 0 | 2025-10-30 20:10:18 | 3 | 0 | 2 | 1 | allLoaded | 158 | 0 | 158 | 0 | +| test | s | | a | 0 | 2025-10-30 20:10:18 | 3 | 0 | 1 | 1 | allLoaded | 155 | 0 | 155 | 0 | +| test | s | | idx | 1 | 2025-10-30 20:10:18 | 3 | 0 | 0 | 0 | allLoaded | 158 | 0 | 158 | 0 | +| test | s | | idx | 1 | 2025-10-30 20:10:18 | 3 | 0 | 0 | 0 | allLoaded | 155 | 0 | 155 | 0 | ++---------+------------+----------------+-------------+----------+---------------------+----------------+------------+--------------+-------------+-------------+-----------------+----------------+----------------+---------------+ +4 rows in set (0.008 sec) +``` + +```sql +ADMIN SHOW DDL JOBS 1; +``` + +``` ++--------+---------+------------------+---------------+----------------------+-----------+----------+-----------+----------------------------+----------------------------+----------------------------+---------+-----------------------------+ +| JOB_ID | DB_NAME | TABLE_NAME | JOB_TYPE | SCHEMA_STATE | SCHEMA_ID | TABLE_ID | ROW_COUNT | CREATE_TIME | START_TIME | END_TIME | STATE | COMMENTS | ++--------+---------+------------------+---------------+----------------------+-----------+----------+-----------+----------------------------+----------------------------+----------------------------+---------+-----------------------------+ +| 153 | test | s | modify column | write reorganization | 2 | 148 | 12582912 | 2025-10-29 00:26:49.240000 | 2025-10-29 00:26:49.244000 | NULL | running | analyzing | ++--------+---------+------------------+---------------+----------------------+-----------+----------+-----------+----------------------------+----------------------------+----------------------------+---------+-----------------------------+ +1 rows in set (0.001 sec) +``` + +From the `MODIFY COLUMN` example, when `tidb_stats_update_during_ddl` is `ON`, you can see that after the execution of the `MODIFY COLUMN` DDL statement, the subsequent `EXPLAIN` output shows that statistics for the index `idx` have been automatically collected and loaded into memory (you can verify it by executing `SHOW STATS_HISTOGRAMS`). As a result, the optimizer can immediately use these statistics for range scans. If index creation or reorganization and `ANALYZE` take a long time, you can check the DDL job status by executing `ADMIN SHOW DDL JOBS`. When the `COMMENTS` column in the output contains `analyzing`, it means that the DDL job is collecting statistics. diff --git a/system-variables.md b/system-variables.md index 6ad5c710e3ace..e8ce03fa70656 100644 --- a/system-variables.md +++ b/system-variables.md @@ -1624,6 +1624,14 @@ mysql> SELECT job_info FROM mysql.analyze_jobs ORDER BY end_time DESC LIMIT 1; +### tidb_stats_update_during_ddl New in v8.5.4 and v9.0.0 + +- Scope: GLOBAL +- Persists to cluster: Yes +- Applies to hint [SET_VAR](/optimizer-hints.md#set_varvar_namevar_value): No +- Default value: `OFF` +- This variable controls whether to enable DDL-embedded `ANALYZE`. When enabled, DDL statements that create new indexes ([`ADD INDEX`](/sql-statements/sql-statement-add-index.md)) or reorganize existing indexes ([`MODIFY COLUMN`](/sql-statements/sql-statement-modify-column.md) and [`CHANGE COLUMN`](/sql-statements/sql-statement-change-column.md)) automatically collect statistics before the index becomes visible. For more information, see [`ANALYZE` Embedded in DDL Statements](/ddl_embedded_analyze.md). + ### tidb_enable_dist_task New in v7.1.0 - Scope: GLOBAL From 0693593c606b7d86f4d13fe672528a3732fd8291 Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Mon, 10 Nov 2025 14:39:46 +0800 Subject: [PATCH 03/12] planner: Add subquery variables (#21943) (#22028) --- system-variables.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/system-variables.md b/system-variables.md index e8ce03fa70656..3b9829bd8dc57 100644 --- a/system-variables.md +++ b/system-variables.md @@ -4305,6 +4305,24 @@ mysql> desc select count(distinct a) from test.t; - Default value: `OFF` - This variable controls whether to enable the [Cross-database binding](/sql-plan-management.md#cross-database-binding) feature. +### tidb_opt_enable_no_decorrelate_in_select New in v8.5.4 + +- Scope: SESSION | GLOBAL +- Persists to cluster: Yes +- Applies to hint [SET_VAR](/optimizer-hints.md#set_varvar_namevar_value): Yes +- Type: Boolean +- Default value: `OFF` +- This variable controls whether the optimizer applies the [`NO_DECORRELATE()`](/optimizer-hints.md#no_decorrelate) hint for all queries that contain a subquery in the `SELECT` list. + +### tidb_opt_enable_semi_join_rewrite New in v8.5.4 + +- Scope: SESSION | GLOBAL +- Persists to cluster: Yes +- Applies to hint [SET_VAR](/optimizer-hints.md#set_varvar_namevar_value): No +- Type: Boolean +- Default value: `OFF` +- This variable controls whether the optimizer applies the [`SEMI_JOIN_REWRITE()`](/optimizer-hints.md#semi_join_rewrite) hint for all queries that contain subqueries. + ### tidb_opt_fix_control New in v6.5.3 and v7.1.0 From 16e79fe1386eb50cde60e72377d0472d220d448f Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Mon, 10 Nov 2025 16:52:43 +0800 Subject: [PATCH 04/12] v8.5.4: partitioned-table: global index supports non-unique index (#19944) (#21879) --- partitioned-table.md | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/partitioned-table.md b/partitioned-table.md index 5bc8b7f31522e..3782ac0ab9f94 100644 --- a/partitioned-table.md +++ b/partitioned-table.md @@ -1699,13 +1699,13 @@ CREATE TABLE t (a varchar(20), b blob, ERROR 8264 (HY000): Global Index is needed for index 'a', since the unique index is not including all partitioning columns, and GLOBAL is not given as IndexOption ``` -#### Global indexes +### Global indexes Before the introduction of global indexes, TiDB created a local index for each partition, leading to [a limitation](#partitioning-keys-primary-keys-and-unique-keys) that primary keys and unique keys had to include the partition key to ensure data uniqueness. Additionally, when querying data across multiple partitions, TiDB needed to scan the data of each partition to return results. -To address these issues, TiDB introduces the global indexes feature in v8.3.0. A global index covers the data of the entire table with a single index, allowing primary keys and unique keys to maintain global uniqueness without including all partition keys. Moreover, global indexes can access index data across multiple partitions in a single operation, significantly improving query performance for non-partitioned keys instead of looking up in one local index for each partition. +To address these issues, TiDB introduces the global indexes feature in v8.3.0. A global index covers the data of the entire table with a single index, allowing primary keys and unique keys to maintain global uniqueness without including all partition keys. Moreover, global indexes can access index data across multiple partitions in a single operation instead of looking up the local index for each partition, significantly improving query performance for non-partitioned keys. Starting from v8.5.4, non-unique indexes can also be created as global indexes. -To create a global index for a primary key or unique key, you can add the `GLOBAL` keyword in the index definition. +To create a global index, you can add the `GLOBAL` keyword in the index definition. > **Note:** > @@ -1718,13 +1718,14 @@ CREATE TABLE t1 ( col3 INT NOT NULL, col4 INT NOT NULL, UNIQUE KEY uidx12(col1, col2) GLOBAL, - UNIQUE KEY uidx3(col3) + UNIQUE KEY uidx3(col3), + KEY idx1(col1) GLOBAL ) PARTITION BY HASH(col3) PARTITIONS 4; ``` -In the preceding example, the unique index `uidx12` is a global index, while `uidx3` is a regular unique index. +In the preceding example, the unique index `uidx12` and non-unique index `idx1` are global indexes, while `uidx3` is a regular unique index. Note that a **clustered index** cannot be a global index, as shown in the following example: @@ -1756,7 +1757,8 @@ Create Table: CREATE TABLE `t1` ( `col3` int NOT NULL, `col4` int NOT NULL, UNIQUE KEY `uidx12` (`col1`,`col2`) /*T![global_index] GLOBAL */, - UNIQUE KEY `uidx3` (`col3`) + UNIQUE KEY `uidx3` (`col3`), + KEY `idx1` (`col1`) /*T![global_index] GLOBAL */ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin PARTITION BY HASH (`col3`) PARTITIONS 4 1 row in set (0.00 sec) @@ -1775,26 +1777,23 @@ SELECT * FROM INFORMATION_SCHEMA.TIDB_INDEXES WHERE table_name='t1'; | test | t1 | 0 | uidx12 | 1 | col1 | NULL | | NULL | 1 | YES | NO | 1 | | test | t1 | 0 | uidx12 | 2 | col2 | NULL | | NULL | 1 | YES | NO | 1 | | test | t1 | 0 | uidx3 | 1 | col3 | NULL | | NULL | 2 | YES | NO | 0 | +| test | t1 | 1 | idx1 | 1 | col1 | NULL | | NULL | 3 | YES | NO | 1 | +--------------+------------+------------+----------+--------------+-------------+----------+---------------+------------+----------+------------+-----------+-----------+ 3 rows in set (0.00 sec) ``` -When partitioning a non-partitioned table or repartitioning an already partitioned table, you can update the indexes to be global indexes or revert them to local indexes as needed: +When partitioning a non-partitioned table or repartitioning an already partitioned table, you can update the indexes to be global indexes or local indexes as needed. + +For example, the following SQL statement repartitions table `t1` based on the `col1` column, updates the global indexes `uidx12` and `idx1` to local indexes, and updates the local index `uidx3` to a global index. Because `uidx3` is a unique index on the `col3` column, it must be a global index to ensure the uniqueness of `col3` across all partitions. `uidx12` and `idx1` are indexes on the `col1` column, which means they can be either global or local indexes. ```sql -ALTER TABLE t1 PARTITION BY HASH (col1) PARTITIONS 3 UPDATE INDEXES (uidx12 LOCAL, uidx3 GLOBAL); +ALTER TABLE t1 PARTITION BY HASH (col1) PARTITIONS 3 UPDATE INDEXES (uidx12 LOCAL, uidx3 GLOBAL, idx1 LOCAL); ``` -##### Limitations of global indexes +#### Limitations of global indexes - If the `GLOBAL` keyword is not explicitly specified in the index definition, TiDB creates a local index by default. - The `GLOBAL` and `LOCAL` keywords only apply to partitioned tables and do not affect non-partitioned tables. In other words, there is no difference between a global index and a local index in non-partitioned tables. -- Currently, TiDB only supports creating unique global indexes on unique columns. If you need to create a global index on a non-unique column, you can include a primary key in the global index to create a composite index. For example, if the non-unique column is `col3` and the primary key is `col1`, you can use the following statement to create a global index on the non-unique column `col3`: - - ```sql - ALTER TABLE ... ADD UNIQUE INDEX(col3, col1) GLOBAL; - ``` - - DDL operations such as `DROP PARTITION`, `TRUNCATE PARTITION`, and `REORGANIZE PARTITION` also trigger updates to global indexes. These DDL operations need to wait for the global index updates to complete before returning results, which increases the execution time accordingly. This is particularly evident in data archiving scenarios, such as `DROP PARTITION` and `TRUNCATE PARTITION`. Without global indexes, these operations can typically complete immediately. However, with global indexes, the execution time increases as the number of indexes that need to be updated grows. - Tables with global indexes do not support the `EXCHANGE PARTITION` operation. - By default, the primary key of a partitioned table is a clustered index and must include the partition key. If you require the primary key to exclude the partition key, you can explicitly specify the primary key as a non-clustered global index when creating the table, for example, `PRIMARY KEY(col1, col2) NONCLUSTERED GLOBAL`. @@ -1928,7 +1927,7 @@ select * from t; 5 rows in set (0.00 sec) ``` -### Dynamic pruning mode +## Dynamic pruning mode TiDB accesses partitioned tables in either `dynamic` or `static` mode. `dynamic` mode is used by default since v6.3.0. However, dynamic partitioning is effective only after the full table-level statistics, or global statistics, are collected. If you enable the `dynamic` pruning mode before global statistics collection is completed, TiDB remains in the `static` mode until global statistics are fully collected. For detailed information about global statistics, see [Collect statistics of partitioned tables in dynamic pruning mode](/statistics.md#collect-statistics-of-partitioned-tables-in-dynamic-pruning-mode). @@ -2133,7 +2132,7 @@ From example 2, you can see that in `dynamic` mode, the execution plan with Inde Currently, `static` pruning mode does not support plan cache for both prepared and non-prepared statements. -#### Update statistics of partitioned tables in dynamic pruning mode +### Update statistics of partitioned tables in dynamic pruning mode 1. Locate all partitioned tables: From 6e11a8a4a4196e1e5a5fdfc1285f5008478ec848 Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Mon, 10 Nov 2025 16:52:51 +0800 Subject: [PATCH 05/12] v8.5.4: distribute-table: support to scatter the region distribution of the given table and engine (#20345) (#21883) --- TOC-tidb-cloud.md | 4 + TOC.md | 4 + .../sql-statement-cancel-distribution-job.md | 46 +++++++ .../sql-statement-distribute-table.md | 128 ++++++++++++++++++ .../sql-statement-show-distribution-jobs.md | 51 +++++++ .../sql-statement-show-table-distribution.md | 69 ++++++++++ 6 files changed, 302 insertions(+) create mode 100644 sql-statements/sql-statement-cancel-distribution-job.md create mode 100644 sql-statements/sql-statement-distribute-table.md create mode 100644 sql-statements/sql-statement-show-distribution-jobs.md create mode 100644 sql-statements/sql-statement-show-table-distribution.md diff --git a/TOC-tidb-cloud.md b/TOC-tidb-cloud.md index edca58a37e1f0..749d010af8e4e 100644 --- a/TOC-tidb-cloud.md +++ b/TOC-tidb-cloud.md @@ -429,6 +429,7 @@ - [`BACKUP`](/sql-statements/sql-statement-backup.md) - [`BATCH`](/sql-statements/sql-statement-batch.md) - [`BEGIN`](/sql-statements/sql-statement-begin.md) + - [`CANCEL DISTRIBUTION JOB`](/sql-statements/sql-statement-cancel-distribution-job.md) - [`CANCEL IMPORT JOB`](/sql-statements/sql-statement-cancel-import-job.md) - [`COMMIT`](/sql-statements/sql-statement-commit.md) - [`CREATE [GLOBAL|SESSION] BINDING`](/sql-statements/sql-statement-create-binding.md) @@ -446,6 +447,7 @@ - [`DELETE`](/sql-statements/sql-statement-delete.md) - [`DESC`](/sql-statements/sql-statement-desc.md) - [`DESCRIBE`](/sql-statements/sql-statement-describe.md) + - [`DISTRIBUTE TABLE`](/sql-statements/sql-statement-distribute-table.md) - [`DO`](/sql-statements/sql-statement-do.md) - [`DROP [GLOBAL|SESSION] BINDING`](/sql-statements/sql-statement-drop-binding.md) - [`DROP DATABASE`](/sql-statements/sql-statement-drop-database.md) @@ -509,6 +511,7 @@ - [`SHOW CREATE TABLE`](/sql-statements/sql-statement-show-create-table.md) - [`SHOW CREATE USER`](/sql-statements/sql-statement-show-create-user.md) - [`SHOW DATABASES`](/sql-statements/sql-statement-show-databases.md) + - [`SHOW DISTRIBUTION JOBS`](/sql-statements/sql-statement-show-distribution-jobs.md) - [`SHOW ENGINES`](/sql-statements/sql-statement-show-engines.md) - [`SHOW ERRORS`](/sql-statements/sql-statement-show-errors.md) - [`SHOW FIELDS FROM`](/sql-statements/sql-statement-show-fields-from.md) @@ -531,6 +534,7 @@ - [`SHOW STATS_META`](/sql-statements/sql-statement-show-stats-meta.md) - [`SHOW STATS_TOPN`](/sql-statements/sql-statement-show-stats-topn.md) - [`SHOW STATUS`](/sql-statements/sql-statement-show-status.md) + - [`SHOW TABLE DISTRIBUTION`](/sql-statements/sql-statement-show-table-distribution.md) - [`SHOW TABLE NEXT_ROW_ID`](/sql-statements/sql-statement-show-table-next-rowid.md) - [`SHOW TABLE REGIONS`](/sql-statements/sql-statement-show-table-regions.md) - [`SHOW TABLE STATUS`](/sql-statements/sql-statement-show-table-status.md) diff --git a/TOC.md b/TOC.md index 8e7fb55126249..ddf4854a77dc7 100644 --- a/TOC.md +++ b/TOC.md @@ -813,6 +813,7 @@ - [`BATCH`](/sql-statements/sql-statement-batch.md) - [`BEGIN`](/sql-statements/sql-statement-begin.md) - [`CALIBRATE RESOURCE`](/sql-statements/sql-statement-calibrate-resource.md) + - [`CANCEL DISTRIBUTION JOB`](/sql-statements/sql-statement-cancel-distribution-job.md) - [`CANCEL IMPORT JOB`](/sql-statements/sql-statement-cancel-import-job.md) - [`COMMIT`](/sql-statements/sql-statement-commit.md) - [`CREATE BINDING`](/sql-statements/sql-statement-create-binding.md) @@ -830,6 +831,7 @@ - [`DELETE`](/sql-statements/sql-statement-delete.md) - [`DESC`](/sql-statements/sql-statement-desc.md) - [`DESCRIBE`](/sql-statements/sql-statement-describe.md) + - [`DISTRIBUTE TABLE`](/sql-statements/sql-statement-distribute-table.md) - [`DO`](/sql-statements/sql-statement-do.md) - [`DROP BINDING`](/sql-statements/sql-statement-drop-binding.md) - [`DROP DATABASE`](/sql-statements/sql-statement-drop-database.md) @@ -894,6 +896,7 @@ - [`SHOW CREATE TABLE`](/sql-statements/sql-statement-show-create-table.md) - [`SHOW CREATE USER`](/sql-statements/sql-statement-show-create-user.md) - [`SHOW DATABASES`](/sql-statements/sql-statement-show-databases.md) + - [`SHOW DISTRIBUTION JOBS`](/sql-statements/sql-statement-show-distribution-jobs.md) - [`SHOW ENGINES`](/sql-statements/sql-statement-show-engines.md) - [`SHOW ERRORS`](/sql-statements/sql-statement-show-errors.md) - [`SHOW FIELDS FROM`](/sql-statements/sql-statement-show-fields-from.md) @@ -916,6 +919,7 @@ - [`SHOW STATS_META`](/sql-statements/sql-statement-show-stats-meta.md) - [`SHOW STATS_TOPN`](/sql-statements/sql-statement-show-stats-topn.md) - [`SHOW STATUS`](/sql-statements/sql-statement-show-status.md) + - [`SHOW TABLE DISTRIBUTION`](/sql-statements/sql-statement-show-table-distribution.md) - [`SHOW TABLE NEXT_ROW_ID`](/sql-statements/sql-statement-show-table-next-rowid.md) - [`SHOW TABLE REGIONS`](/sql-statements/sql-statement-show-table-regions.md) - [`SHOW TABLE STATUS`](/sql-statements/sql-statement-show-table-status.md) diff --git a/sql-statements/sql-statement-cancel-distribution-job.md b/sql-statements/sql-statement-cancel-distribution-job.md new file mode 100644 index 0000000000000..5cc3f28161b77 --- /dev/null +++ b/sql-statements/sql-statement-cancel-distribution-job.md @@ -0,0 +1,46 @@ +--- +title: CANCEL DISTRIBUTION JOB +summary: An overview of the usage of CANCEL DISTRIBUTION JOB in TiDB. +--- + +# CANCEL DISTRIBUTION JOB New in v8.5.4 + +The `CANCEL DISTRIBUTION JOB` statement is used to cancel a Region scheduling task created using the [`DISTRIBUTE TABLE`](/sql-statements/sql-statement-distribute-table.md) statement in TiDB. + + + +> **Note:** +> +> This feature is not available on [{{{ .starter }}}](https://docs.pingcap.com/tidbcloud/select-cluster-tier#tidb-cloud-serverless) and [{{{ .essential }}}](https://docs.pingcap.com/tidbcloud/select-cluster-tier#essential) clusters. + + + +## Synopsis + +```ebnf+diagram +CancelDistributionJobsStmt ::= + 'CANCEL' 'DISTRIBUTION' 'JOB' JobID +``` + +## Examples + +The following example cancels the distribution job with ID `1`: + +```sql +CANCEL DISTRIBUTION JOB 1; +``` + +The output is as follows: + +``` +Query OK, 0 rows affected (0.01 sec) +``` + +## MySQL compatibility + +This statement is a TiDB extension to MySQL syntax. + +## See also + +* [`DISTRIBUTE TABLE`](/sql-statements/sql-statement-distribute-table.md) +* [`SHOW DISTRIBUTION JOBS`](/sql-statements/sql-statement-show-distribution-jobs.md) \ No newline at end of file diff --git a/sql-statements/sql-statement-distribute-table.md b/sql-statements/sql-statement-distribute-table.md new file mode 100644 index 0000000000000..89ff8803eb34a --- /dev/null +++ b/sql-statements/sql-statement-distribute-table.md @@ -0,0 +1,128 @@ +--- +title: DISTRIBUTE TABLE +summary: An overview of the usage of DISTRIBUTE TABLE for the TiDB database. +--- + +# DISTRIBUTE TABLE New in v8.5.4 + +> **Warning:** +> +> This feature is experimental. It is not recommended that you use it in the production environment. This feature might be changed or removed without prior notice. If you find a bug, you can report an [issue](https://github.com/pingcap/tidb/issues) on GitHub. + + + +> **Note:** +> +> This feature is not available on [{{{ .starter }}}](https://docs.pingcap.com/tidbcloud/select-cluster-tier#tidb-cloud-serverless) and [{{{ .essential }}}](https://docs.pingcap.com/tidbcloud/select-cluster-tier#essential) clusters. + + + +The `DISTRIBUTE TABLE` statement redistributes and reschedules Regions of a specified table to achieve a balanced distribution at the table level. Executing this statement helps prevent Regions from being concentrated on a few TiFlash or TiKV nodes, addressing the issue of uneven region distribution in the table. + +## Synopsis + +```ebnf+diagram +DistributeTableStmt ::= + "DISTRIBUTE" "TABLE" TableName PartitionNameListOpt "RULE" EqOrAssignmentEq Identifier "ENGINE" EqOrAssignmentEq Identifier "TIMEOUT" EqOrAssignmentEq Identifier + +TableName ::= + (SchemaName ".")? Identifier + +PartitionNameList ::= + "PARTITION" "(" PartitionName ("," PartitionName)* ")" +``` + +## Parameter description + +When redistributing Regions in a table using the `DISTRIBUTE TABLE` statement, you can specify the storage engine (such as TiFlash or TiKV) and different Raft roles (such as Leader, Learner, or Voter) for balanced distribution. + +- `RULE`: specifies which Raft role's Region to balance and schedule. Optional values are `"leader-scatter"`, `"peer-scatter"`, and `"learner-scatter"`. +- `ENGINE`: specifies the storage engine. Optional values are `"tikv"` and `"tiflash"`. +- `TIMEOUT`: specifies the timeout limit for the scatter operation. If PD does not complete the scatter within this time, the scatter task will automatically exit. When this parameter is not specified, the default value is `"30m"`. + +## Examples + +Redistribute the Regions of the Leaders in the table `t1` on TiKV: + +```sql +CREATE TABLE t1 (a INT); +... +DISTRIBUTE TABLE t1 RULE = "leader-scatter" ENGINE = "tikv" TIMEOUT = "1h"; +``` + +``` ++--------+ +| JOB_ID | ++--------+ +| 100 | ++--------+ +``` + +Redistribute the Regions of the Learners in the table `t2` on TiFlash: + +```sql +CREATE TABLE t2 (a INT); +... +DISTRIBUTE TABLE t2 RULE = "learner-scatter" ENGINE = "tiflash"; +``` + +``` ++--------+ +| JOB_ID | ++--------+ +| 101 | ++--------+ +``` + +Redistribute the Regions of the Peers in the table `t3`'s `p1` and `p2` partitions on TiKV: + +```sql +CREATE TABLE t3 ( a INT, b INT, INDEX idx(b)) PARTITION BY RANGE( a ) ( + PARTITION p1 VALUES LESS THAN (10000), + PARTITION p2 VALUES LESS THAN (20000), + PARTITION p3 VALUES LESS THAN (MAXVALUE) ); +... +DISTRIBUTE TABLE t3 PARTITION (p1, p2) RULE = "peer-scatter" ENGINE = "tikv"; +``` + +``` ++--------+ +| JOB_ID | ++--------+ +| 102 | ++--------+ +``` + +Redistribute the Regions of the Learner in the table `t4`'s `p1` and `p2` partitions on TiFlash: + +```sql +CREATE TABLE t4 ( a INT, b INT, INDEX idx(b)) PARTITION BY RANGE( a ) ( + PARTITION p1 VALUES LESS THAN (10000), + PARTITION p2 VALUES LESS THAN (20000), + PARTITION p3 VALUES LESS THAN (MAXVALUE) ); +... +DISTRIBUTE TABLE t4 PARTITION (p1, p2) RULE = "learner-scatter" ENGINE="tiflash"; +``` + +``` ++--------+ +| JOB_ID | ++--------+ +| 103 | ++--------+ +``` + +## Notes + +When you execute the `DISTRIBUTE TABLE` statement to redistribute Regions of a table, the Region distribution result might be affected by the PD hotspot scheduler. After the redistribution, the Region distribution of this table might become imbalanced again over time. + +## MySQL compatibility + +This statement is a TiDB extension to MySQL syntax. + +## See also + +- [`SHOW DISTRIBUTION JOBS`](/sql-statements/sql-statement-show-distribution-jobs.md) +- [`SHOW TABLE DISTRIBUTION`](/sql-statements/sql-statement-show-table-distribution.md) +- [`SHOW TABLE REGIONS`](/sql-statements/sql-statement-show-table-regions.md) +- [`CANCEL DISTRIBUTION JOB`](/sql-statements/sql-statement-cancel-distribution-job.md) \ No newline at end of file diff --git a/sql-statements/sql-statement-show-distribution-jobs.md b/sql-statements/sql-statement-show-distribution-jobs.md new file mode 100644 index 0000000000000..f7d1ec48f0ad0 --- /dev/null +++ b/sql-statements/sql-statement-show-distribution-jobs.md @@ -0,0 +1,51 @@ +--- +title: SHOW DISTRIBUTION JOBS +summary: An overview of the usage of SHOW DISTRIBUTION JOBS for the TiDB database. +--- + +# SHOW DISTRIBUTION JOBS New in v8.5.4 + +The `SHOW DISTRIBUTION JOBS` statement shows all current Region distribution jobs. + + + +> **Note:** +> +> This feature is not available on [{{{ .starter }}}](https://docs.pingcap.com/tidbcloud/select-cluster-tier#tidb-cloud-serverless) and [{{{ .essential }}}](https://docs.pingcap.com/tidbcloud/select-cluster-tier#essential) clusters. + + + +## Synopsis + +```ebnf+diagram +ShowDistributionJobsStmt ::= + "SHOW" "DISTRIBUTION" "JOBS" +``` + +## Examples + +Show all current Region distribution jobs: + +```sql +SHOW DISTRIBUTION JOBS; +``` + +``` ++--------+----------+-------+----------------+--------+----------------+-----------+---------------------+---------------------+---------------------+ +| Job_ID | Database | Table | Partition_List | Engine | Rule | Status | Create_Time | Start_Time | Finish_Time | ++--------+----------+-------+----------------+--------+----------------+-----------+---------------------+---------------------+---------------------+ +| 100 | test | t1 | NULL | tikv | leader-scatter | finished | 2025-04-24 16:09:55 | 2025-04-24 16:09:55 | 2025-04-24 17:09:59 | +| 101 | test | t2 | NULL | tikv | learner-scatter| cancelled | 2025-05-08 15:33:29 | 2025-05-08 15:33:29 | 2025-05-08 15:33:37 | +| 102 | test | t5 | p1,p2 | tikv | peer-scatter | cancelled | 2025-05-21 15:32:44 | 2025-05-21 15:32:47 | 2025-05-21 15:32:47 | ++--------+----------+-------+----------------+--------+----------------+-----------+---------------------+---------------------+---------------------+ +``` + +## MySQL compatibility + +This statement is a TiDB extension to MySQL syntax. + +## See also + +- [`DISTRIBUTE TABLE`](/sql-statements/sql-statement-distribute-table.md) +- [`SHOW TABLE DISTRIBUTION`](/sql-statements/sql-statement-show-table-distribution.md) +- [`CANCEL DISTRIBUTION JOB`](/sql-statements/sql-statement-cancel-distribution-job.md) \ No newline at end of file diff --git a/sql-statements/sql-statement-show-table-distribution.md b/sql-statements/sql-statement-show-table-distribution.md new file mode 100644 index 0000000000000..489a2194b71f2 --- /dev/null +++ b/sql-statements/sql-statement-show-table-distribution.md @@ -0,0 +1,69 @@ +--- +title: SHOW TABLE DISTRIBUTION +summary: An overview of the usage of SHOW TABLE DISTRIBUTION for the TiDB database. +--- + +# SHOW TABLE DISTRIBUTION New in v8.5.4 + +The `SHOW TABLE DISTRIBUTION` statement shows the Region distribution information for a specified table. + + + +> **Note:** +> +> This feature is not available on [{{{ .starter }}}](https://docs.pingcap.com/tidbcloud/select-cluster-tier#tidb-cloud-serverless) and [{{{ .essential }}}](https://docs.pingcap.com/tidbcloud/select-cluster-tier#essential) clusters. + + + +## Synopsis + +```ebnf+diagram +ShowTableDistributionStmt ::= + "SHOW" "TABLE" TableName "DISTRIBUTIONS" + +TableName ::= + (SchemaName ".")? Identifier +``` + +## Examples + +Show the Region distribution of the table `t`: + +```sql +CREATE TABLE `t` ( + `a` int DEFAULT NULL, + `b` int DEFAULT NULL, + KEY `idx` (`b`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin +PARTITION BY RANGE (`a`) +(PARTITION `p1` VALUES LESS THAN (10000), + PARTITION `p2` VALUES LESS THAN (MAXVALUE)); +SHOW TABLE t DISTRIBUTIONS; +``` + +``` ++----------------+----------+------------+---------------------+-------------------+--------------------+-------------------+--------------------+--------------------------+-------------------------+--------------------------+------------------------+-----------------------+------------------------+ +| PARTITION_NAME | STORE_ID | STORE_TYPE | REGION_LEADER_COUNT | REGION_PEER_COUNT | REGION_WRITE_BYTES | REGION_WRITE_KEYS | REGION_WRITE_QUERY | REGION_LEADER_READ_BYTES | REGION_LEADER_READ_KEYS | REGION_LEADER_READ_QUERY | REGION_PEER_READ_BYTES | REGION_PEER_READ_KEYS | REGION_PEER_READ_QUERY | ++----------------+----------+------------+---------------------+-------------------+--------------------+-------------------+--------------------+--------------------------+-------------------------+--------------------------+------------------------+-----------------------+------------------------+ +| p1 | 1 | tikv | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| p1 | 15 | tikv | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| p1 | 4 | tikv | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| p1 | 5 | tikv | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| p1 | 6 | tikv | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| p2 | 1 | tikv | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| p2 | 15 | tikv | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| p2 | 4 | tikv | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| p2 | 5 | tikv | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | +| p2 | 6 | tikv | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ++----------------+----------+------------+---------------------+-------------------+--------------------+-------------------+--------------------+--------------------------+-------------------------+--------------------------+------------------------+-----------------------+------------------------+ +``` + +## MySQL compatibility + +This statement is a TiDB extension to MySQL syntax. + +## See also + +- [`DISTRIBUTE TABLE`](/sql-statements/sql-statement-distribute-table.md) +- [`SHOW DISTRIBUTION JOBS`](/sql-statements/sql-statement-show-distribution-jobs.md) +- [`CANCEL DISTRIBUTION JOB`](/sql-statements/sql-statement-cancel-distribution-job.md) \ No newline at end of file From 01ed82432bc84bade3f2703bbc3b8cbf563701df Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Mon, 10 Nov 2025 16:57:40 +0800 Subject: [PATCH 06/12] v8.5.4: reference: update doc for follower read (#21962) (#22000) --- follower-read.md | 84 +++++++++++++++++++++++++---- grafana-tidb-dashboard.md | 7 ++- media/follower-read/read-index.png | Bin 0 -> 50514 bytes system-variables.md | 2 +- 4 files changed, 82 insertions(+), 11 deletions(-) create mode 100644 media/follower-read/read-index.png diff --git a/follower-read.md b/follower-read.md index 76156e996f61a..672263f7880c3 100644 --- a/follower-read.md +++ b/follower-read.md @@ -5,15 +5,36 @@ summary: This document describes the use and implementation of Follower Read. # Follower Read -When a read hotspot appears in a Region, the Region leader can become a read bottleneck for the entire system. In this situation, enabling the Follower Read feature can significantly reduce the load of the leader, and improve the throughput of the whole system by balancing the load among multiple followers. This document introduces the use and implementation mechanism of Follower Read. +In TiDB, to ensure high availability and data safety, TiKV stores multiple replicas for each Region, one of which is the leader and the others are followers. By default, all read and write requests are processed by the leader. The Follower Read feature enables TiDB to read data from follower replicas of a Region while maintaining strong consistency, thereby reducing the read workload on the leader and improving the overall read throughput of the cluster. -## Overview + + +When performing Follower Read, TiDB selects an appropriate replica based on the topology information. Specifically, TiDB uses the `zone` label to identify local replicas: if the `zone` label of a TiDB node is the same as that of the target TiKV node, TiDB considers the replica as a local replica. For more information, see [Schedule Replicas by Topology Labels](/schedule-replicas-by-topology-labels.md). + + + + + +When performing Follower Read, TiDB selects an appropriate replica based on the topology information. Specifically, TiDB uses the `zone` label to identify local replicas: if the `zone` label of a TiDB node is the same as that of the target TiKV node, TiDB considers the replica as a local replica. The `zone` label is set automatically in TiDB Cloud. + + -The Follower Read feature refers to using any follower replica of a Region to serve a read request under the premise of strongly consistent reads. This feature improves the throughput of the TiDB cluster and reduces the load of the leader. It contains a series of load balancing mechanisms that offload TiKV read loads from the leader replica to the follower replica in a Region. TiKV's Follower Read implementation provides users with strongly consistent reads. +By enabling followers to handle read requests, Follower Read achieves the following goals: + +- Distribute read hotspots and reduce the leader workload. +- Prioritize local replica reads in multi-AZ or multi-datacenter deployments to minimize cross-AZ traffic. + +## Usage scenarios + +Follower Read is suitable for the following scenarios: + +- Applications with heavy read requests or significant read hotspots. +- Multi-AZ deployments where you want to prioritize reading from local replicas to reduce cross-AZ bandwidth usage. +- Read-write separation architectures that you want to further improve overall read performance. > **Note:** > -> To achieve strongly consistent reads, the follower node currently needs to request the current execution progress from the leader node (that is `ReadIndex`), which causes an additional network request overhead. Therefore, the main benefits of Follower Read are to isolate read requests from write requests in the cluster and to increase overall read throughput. +> To ensure strong consistency of the read results, Follower Read communicates with the leader before reading to confirm the latest commit progress (by executing the Raft `ReadIndex` operation). This introduces an additional network interaction. Therefore, Follower Read is most effective where a large number of read requests exist or read-write isolation is required. However, for low-latency single queries, the performance improvement might not be significant. ## Usage @@ -29,7 +50,24 @@ Scope: SESSION | GLOBAL Default: leader -This variable is used to set the expected data read mode. +This variable defines the expected data read mode. Starting from v8.5.4, this variable only takes effect on read-only SQL statements. + +In scenarios where you need to reduce cross-AZ traffic by reading from local replicas, the following configurations are recommended: + +- `leader`: the default value, providing the best performance. +- `closest-adaptive`: minimizes cross-AZ traffic while keeping performance loss to a minimum. +- `closest-replicas`: maximizes cross-AZ traffic savings but might cause some performance degradation. + +If you are using other configurations, refer to the following table to modify them to the recommended configurations: + +| Current configuration | Recommended configuration | +| ------------- | ------------- | +| `follower` | `closest-replicas` | +| `leader-and-follower` | `closest-replicas` | +| `prefer-leader` | `closest-adaptive` | +| `learner` | `closest-replicas` | + +If you want to use a more precise read replica selection policy, refer to the full list of available configurations as follows: - When you set the value of `tidb_replica_read` to `leader` or an empty string, TiDB maintains its default behavior and sends all read operations to the leader replica to perform. - When you set the value of `tidb_replica_read` to `follower`, TiDB selects a follower replica of the Region to perform read operations. If the Region has learner replicas, TiDB also considers them for reads with the same priority. If no available follower or learner replicas exist for the current Region, TiDB reads from the leader replica. @@ -56,18 +94,46 @@ This variable is used to set the expected data read mode. + + +## Basic monitoring + +You can check the [**TiDB** > **KV Request** > **Read Req Traffic** panel (New in v8.5.4)](/grafana-tidb-dashboard.md#kv-request) to determine whether to enable Follower Read and observe the traffic reduction effect after enabling it. + + + ## Implementation mechanism -Before the Follower Read feature was introduced, TiDB applied the strong leader principle and submitted all read and write requests to the leader node of a Region to handle. Although TiKV can distribute Regions evenly on multiple physical nodes, for each Region, only the leader can provide external services. The other followers can do nothing to handle read requests but receive the data replicated from the leader at all times and prepare for voting to elect a leader in case of a failover. +Before the Follower Read feature was introduced, TiDB applied the strong leader principle and submitted all read and write requests to the leader node of a Region to handle. Although TiKV can distribute Regions evenly on multiple physical nodes, for each Region, only the leader can provide external services. The other followers cannot handle read requests, and they only receive the data replicated from the leader at all times and prepare for voting to elect a leader in case of a failover. -To allow data reading in the follower node without violating linearizability or affecting Snapshot Isolation in TiDB, the follower node needs to use `ReadIndex` of the Raft protocol to ensure that the read request can read the latest data that has been committed on the leader. At the TiDB level, the Follower Read feature simply needs to send the read request of a Region to a follower replica based on the load balancing policy. +Follower Read includes a set of load balancing mechanisms that offload TiKV read requests from the leader replica to a follower replica in a Region. To allow data reading from the follower node without violating linearizability or affecting Snapshot Isolation in TiDB, the follower node needs to use `ReadIndex` of the Raft protocol to ensure that the read request can read the latest data that has been committed on the leader node. At the TiDB level, the Follower Read feature simply needs to send the read request of a Region to a follower replica based on the load balancing policy. ### Strongly consistent reads When the follower node processes a read request, it first uses `ReadIndex` of the Raft protocol to interact with the leader of the Region, to obtain the latest commit index of the current Raft group. After the latest commit index of the leader is applied locally to the follower, the processing of a read request starts. +![read-index-flow](/media/follower-read/read-index.png) + ### Follower replica selection strategy -Because the Follower Read feature does not affect TiDB's Snapshot Isolation transaction isolation level, TiDB adopts the round-robin strategy to select the follower replica. Currently, for the coprocessor requests, the granularity of the Follower Read load balancing policy is at the connection level. For a TiDB client connected to a specific Region, the selected follower is fixed, and is switched only when it fails or the scheduling policy is adjusted. +The Follower Read feature does not affect TiDB's Snapshot Isolation transaction isolation level. TiDB selects a replica based on the `tidb_replica_read` configuration for the first read attempt. From the second retry onward, TiDB prioritizes ensuring successful reads. Therefore, when the selected follower node becomes inaccessible or has other errors, TiDB switches to the leader for service. + +#### `leader` + +- Always selects the leader replica for reads, regardless of its location. + +#### `closest-replicas` + +- When the replica in the same AZ as TiDB is the leader node, TiDB does not perform Follower Read from it. +- When the replica in the same AZ as TiDB is a follower node, TiDB performs Follower Read from it. + +#### `closest-adaptive` + +- If the estimated result is not large enough, TiDB uses the `leader` policy and does not perform Follower Read. +- If the estimated result is large enough, TiDB uses the `closest-replicas` policy. + +### Follower Read performance overhead + +To ensure strong data consistency, Follower Read performs a `ReadIndex` operation regardless of how much data is read, which inevitably consumes additional TiKV CPU resources. Therefore, in small-query scenarios (such as point queries), the performance loss of Follower Read is relatively more obvious. Moreover, because the traffic reduced by local reads for small queries is limited, Follower Read is more recommended for large queries or batch reading scenarios. -However, for the non-coprocessor requests, such as a point query, the granularity of the Follower Read load balancing policy is at the transaction level. For a TiDB transaction on a specific Region, the selected follower is fixed, and is switched only when it fails or the scheduling policy is adjusted. If a transaction contains both point queries and coprocessor requests, the two types of requests are scheduled for reading separately according to the preceding scheduling policy. In this case, even if a coprocessor request and a point query are for the same Region, TiDB processes them as independent events. +When `tidb_replica_read` is set to `closest-adaptive`, TiDB does not perform Follower Read for small queries. As a result, under various workloads, the additional CPU overhead on TiKV is typically no more than 10% compared with the `leader` policy. diff --git a/grafana-tidb-dashboard.md b/grafana-tidb-dashboard.md index 73d0026926d3e..b7526e1d954ad 100644 --- a/grafana-tidb-dashboard.md +++ b/grafana-tidb-dashboard.md @@ -123,9 +123,14 @@ The following metrics relate to requests sent to TiKV. Retry requests are counte - **local**: the number of requests per second that attempt a stale read in the local zone - Stale Read Req Traffic: - **cross-zone-in**: the incoming traffic of responses to requests that attempt a stale read in a remote zone - - **cross-zone-out**: the outgoing traffic of requests that attempt a stale read in a remote zone + - **cross-zone-out**: the outgoing traffic of responses to requests that attempt a stale read in a remote zone - **local-in**: the incoming traffic of responses to requests that attempt a stale read in the local zone - **local-out**: the outgoing traffic of requests that attempt a stale read in the local zone +- Read Req Traffic + - **leader-local**: traffic generated by Leader Read processing read requests in the local zone + - **leader-cross-zone**: traffic generated by Leader Read processing read requests in a remote zone + - **follower-local**: traffic generated by Follower Read processing read requests in the local zone + - **follower-cross-zone**: traffic generated by Follower Read processing read requests in a remote zone ### PD Client diff --git a/media/follower-read/read-index.png b/media/follower-read/read-index.png new file mode 100644 index 0000000000000000000000000000000000000000..b20a7047f905a9af711f5b740cfc9ac7ec102c9e GIT binary patch literal 50514 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 in v5.2.0 From ba8f4370b7372f42431af26dab72f92059c321dc Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Mon, 10 Nov 2025 16:57:48 +0800 Subject: [PATCH 07/12] v8.5.4: tidb: change the default value of `tidb_mpp_store_fail_ttl` (#21410) (#22015) --- system-variables.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system-variables.md b/system-variables.md index 2abd3e0d07e3c..0f9585d5f4e5b 100644 --- a/system-variables.md +++ b/system-variables.md @@ -4061,8 +4061,8 @@ As shown in this diagram, when [`tidb_enable_paging`](#tidb_enable_paging-new-in - Persists to cluster: Yes - Applies to hint [SET_VAR](/optimizer-hints.md#set_varvar_namevar_value): No - Type: Duration -- Default value: `60s` -- The newly started TiFlash node does not provide services. To prevent queries from failing, TiDB limits the tidb-server sending queries to the newly started TiFlash node. This variable indicates the time range in which the newly started TiFlash node is not sent requests. +- Default value: `0s`. In v8.5.3 and earlier versions, the default value is `60s`. +- The newly started TiFlash node does not provide services. To prevent queries from failing, TiDB limits the tidb-server from sending queries to the newly started TiFlash node. This variable indicates the time range in which the newly started TiFlash node is not sent requests. ### tidb_multi_statement_mode New in v4.0.11 From 7af6c875b081528c80ecc08876cd4bfa2e6fbf89 Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Mon, 10 Nov 2025 16:57:55 +0800 Subject: [PATCH 08/12] v8.5.4: tiflash: add a config named `graceful_shutdown_wait_timeout` (#21734) (#22016) --- tiflash/tiflash-configuration.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tiflash/tiflash-configuration.md b/tiflash/tiflash-configuration.md index b9b907207e0f1..a0af41cb10dba 100644 --- a/tiflash/tiflash-configuration.md +++ b/tiflash/tiflash-configuration.md @@ -241,6 +241,13 @@ The following configuration items only take effect for the TiFlash disaggregated - This configuration item only takes effect for the TiFlash disaggregated storage and compute architecture mode. For details, see [TiFlash Disaggregated Storage and Compute Architecture and S3 Support](/tiflash/tiflash-disaggregated-and-s3.md). - Value options: `"tiflash_write"`, `"tiflash_compute"` +##### `graceful_wait_shutdown_timeout` New in v8.5.4 + +- Controls the maximum wait time when shutting down a TiFlash server. During this period, TiFlash continues running unfinished MPP tasks but does not accept new ones. If all running MPP tasks finish before this timeout, TiFlash shuts down immediately; otherwise, it is forcibly shut down after the wait time expires. +- Default value: `600` +- Unit: seconds +- While the TiFlash server is waiting to shut down (in the grace period), TiDB will not send new MPP tasks to it. + #### flash.proxy ##### `addr` From 7bc750ff35e9e5395c6edcdc85f60cbd53aa00c4 Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Mon, 10 Nov 2025 17:23:16 +0800 Subject: [PATCH 09/12] fix: correct markdown formatting to resolve build failure (#22038) (#22040) --- TOC.md | 2 +- ddl_embedded_analyze.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/TOC.md b/TOC.md index ddf4854a77dc7..f8f91d339e782 100644 --- a/TOC.md +++ b/TOC.md @@ -1083,7 +1083,7 @@ - [URI Formats of External Storage Services](/external-storage-uri.md) - [Interaction Test on Online Workloads and `ADD INDEX` Operations](/benchmark/online-workloads-and-add-index-operations.md) - [`ANALYZE` Embedded in DDL Statements](/ddl_embedded_analyze.md) - FAQs +- FAQs - [FAQ Summary](/faq/faq-overview.md) - [TiDB FAQs](/faq/tidb-faq.md) - [SQL FAQs](/faq/sql-faq.md) diff --git a/ddl_embedded_analyze.md b/ddl_embedded_analyze.md index 9de981b1c2467..d50c1fa12e707 100644 --- a/ddl_embedded_analyze.md +++ b/ddl_embedded_analyze.md @@ -1,9 +1,9 @@ --- -title: `ANALYZE` Embedded in DDL Statements +title: "`ANALYZE` Embedded in DDL Statements" summary: This document describes the `ANALYZE` feature embedded in DDL statements for newly created or reorganized indexes, which ensures that statistics for new indexes are updated promptly. --- -# `ANALYZE` Embedded in DDL StatementsIntroduced in v8.5.4 and v9.0.0 +# `ANALYZE` Embedded in DDL Statements Introduced in v8.5.4 and v9.0.0 This document describes the `ANALYZE` feature embedded in the following two types of DDL statements: From ab01f1c098c62664ffb43005948f8370b9d74faf Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Tue, 18 Nov 2025 15:34:16 +0800 Subject: [PATCH 10/12] v8.5.4: cdc: update description about new architecture (#22031) (#22061) --- ticdc/monitor-ticdc.md | 4 ++- ticdc/ticdc-architecture.md | 67 ++++++++++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/ticdc/monitor-ticdc.md b/ticdc/monitor-ticdc.md index 7f22a0a5994ff..fadd9e0d7fa78 100644 --- a/ticdc/monitor-ticdc.md +++ b/ticdc/monitor-ticdc.md @@ -15,7 +15,9 @@ cdc cli changefeed create --server=http://10.0.10.25:8300 --sink-uri="mysql://ro ## Metrics for TiCDC in the new architecture -The monitoring dashboard **TiCDC-New-Arch** for [TiCDC New Architecture](/ticdc/ticdc-architecture.md) is not managed by TiUP yet. To view the related monitoring data on Grafana, you need to manually import the TiCDC monitoring metrics file: +The monitoring dashboard for [TiCDC in the new architecture](/ticdc/ticdc-architecture.md) is **TiCDC-New-Arch**. For TiDB clusters of v8.5.4 and later versions, this monitoring dashboard is integrated into Grafana during cluster deployment or upgrade, so no manual operation is required. + +If your cluster version is earlier than v8.5.4, you need to manually import the TiCDC monitoring metrics file: 1. Download the monitoring metrics file for TiCDC in the new architecture: diff --git a/ticdc/ticdc-architecture.md b/ticdc/ticdc-architecture.md index 6dd0a66b7b5da..7eb5f15e41f95 100644 --- a/ticdc/ticdc-architecture.md +++ b/ticdc/ticdc-architecture.md @@ -5,7 +5,9 @@ summary: Introduces the features, architectural design, deployment guide, and no # TiCDC New Architecture -Starting from [TiCDC v8.5.4-release.1](https://github.com/pingcap/ticdc/releases/tag/v8.5.4-release.1), TiCDC introduces a new architecture that improves the performance, scalability, and stability of real-time data replication while reducing resource costs. This new architecture redesigns TiCDC core components and optimizes its data processing workflows, offering the following advantages: +Starting from [TiCDC v8.5.4-release.1](https://github.com/pingcap/ticdc/releases/tag/v8.5.4-release.1), TiCDC introduces a new architecture that improves the performance, scalability, and stability of real-time data replication while reducing resource costs. + +This new architecture redesigns TiCDC core components and optimizes its data processing workflows, while maintaining compatibility with the configuration, usage, and APIs of the [classic TiCDC architecture](/ticdc/ticdc-classic-architecture.md). It offers the following advantages: - **Higher single-node performance**: a single node can replicate up to 500,000 tables, achieving replication throughput of up to 190 MiB/s on a single node in wide table scenarios. - **Enhanced scalability**: cluster replication capability scales almost linearly. A single cluster can expand to over 100 nodes, support more than 10,000 changefeeds, and replicate millions of tables within a single changefeed. @@ -102,20 +104,61 @@ In addition, the new TiCDC architecture currently does not support splitting lar ## Upgrade guide -The TiCDC new architecture can only be deployed in TiDB clusters of v7.5.0 or later versions. Before deployment, make sure your TiDB cluster meets this version requirement. +TiCDC in the new architecture can only be deployed in TiDB clusters of v7.5.0 or later versions. Before deployment, make sure your TiDB cluster meets this requirement. + +You can deploy TiCDC nodes in the new architecture using TiUP or TiDB Operator. + +### Deploy a new TiDB cluster with TiCDC nodes in the new architecture + + +
+ +When deploying a new TiDB cluster of v8.5.4 or later using TiUP, you can also deploy TiCDC nodes in the new architecture at the same time. To do so, you only need to add the TiCDC-related section and set `newarch: true` in the configuration file that TiUP uses to start the TiDB cluster. The following is an example: + +```yaml +cdc_servers: + - host: 10.0.1.20 + config: + newarch: true + - host: 10.0.1.21 + config: + newarch: true +``` + +For more TiCDC deployment information, see [Deploy a new TiDB cluster that includes TiCDC using TiUP](/ticdc/deploy-ticdc.md#deploy-a-new-tidb-cluster-that-includes-ticdc-using-tiup). + +
+
+ +When deploying a new TiDB cluster of v8.5.4 or later using TiDB Operator, you can also deploy TiCDC nodes in the new architecture at the same time. To do so, you only need to add the TiCDC-related section and set `newarch = true` in the cluster configuration file. The following is an example: + +```yaml +spec: + ticdc: + baseImage: pingcap/ticdc + version: v8.5.4 + replicas: 3 + config: + newarch = true +``` + +For more TiCDC deployment information, see [Fresh TiCDC deployment](https://docs.pingcap.com/tidb-in-kubernetes/stable/deploy-ticdc/#fresh-ticdc-deployment). + +
+
-You can deploy the TiCDC new architecture using TiUP or TiDB Operator. +### Deploy TiCDC nodes in the new architecture in an existing TiDB cluster
-To deploy the TiCDC new architecture using TiUP, take the following steps: +To deploy TiCDC nodes in the new architecture using TiUP, take the following steps: 1. If your TiDB cluster does not have TiCDC nodes yet, refer to [Scale out a TiCDC cluster](/scale-tidb-using-tiup.md#scale-out-a-ticdc-cluster) to add new TiCDC nodes in the cluster. Otherwise, skip this step. -2. Download the TiCDC binary package for the new architecture. +2. If your TiDB cluster version is earlier than v8.5.4, you need to manually download the TiCDC binary package of the new architecture, and then patch the downloaded file to your TiDB cluster. Otherwise, skip this step. - The download link follows this format: `https://tiup-mirrors.pingcap.com/cdc-${version}-${os}-${arch}.tar.gz`, where `${version}` is the TiCDC version, `${os}` is your operating system, and `${arch}` is the platform the component runs on (`amd64` or `arm64`). + The download link follows this format: `https://tiup-mirrors.pingcap.com/cdc-${version}-${os}-${arch}.tar.gz`, where `${version}` is the TiCDC version (see [TiCDC releases for the new architecture](https://github.com/pingcap/ticdc/releases) for available versions), `${os}` is your operating system, and `${arch}` is the platform the component runs on (`amd64` or `arm64`). For example, to download the binary package of TiCDC v8.5.4-release.1 for Linux (x86-64), run the following command: @@ -158,9 +201,9 @@ To deploy the TiCDC new architecture using TiUP, take the following steps:
-To deploy the TiCDC new architecture using TiDB Operator, take the following steps: +To deploy TiCDC nodes in the new architecture in an existing TiDB cluster using TiDB Operator, take the following steps: -- If your TiDB cluster does not include a TiCDC component, refer to [Add TiCDC to an existing TiDB cluster](https://docs.pingcap.com/tidb-in-kubernetes/stable/deploy-ticdc/#add-ticdc-to-an-existing-tidb-cluster) to add new TiCDC nodes. When doing so, specify the TiCDC image version as the new architecture version in the cluster configuration file. +- If your TiDB cluster does not include a TiCDC component, refer to [Add TiCDC to an existing TiDB cluster](https://docs.pingcap.com/tidb-in-kubernetes/stable/deploy-ticdc/#add-ticdc-to-an-existing-tidb-cluster) to add new TiCDC nodes. When doing so, specify the TiCDC image version as the new architecture version in the cluster configuration file. For available versions, see [TiCDC releases for the new architecture](https://github.com/pingcap/ticdc/releases). For example: @@ -205,7 +248,7 @@ To deploy the TiCDC new architecture using TiDB Operator, take the following ste kubectl apply -f ${cluster_name} -n ${namespace} ``` - 3. Resume all replication tasks: + 3. Resume all replication tasks of the changefeeds: ```shell kubectl exec -it ${pod_name} -n ${namespace} -- sh @@ -223,7 +266,7 @@ To deploy the TiCDC new architecture using TiDB Operator, take the following ste After deploying the TiCDC nodes with the new architecture, you can continue using the same commands as in the classic architecture. There is no need to learn new commands or modify the commands used in the classic architecture. -For example, to create a replication task in a new architecture TiCDC node, run the following command: +For example, to create a replication task for a new TiCDC node in the new architecture, run the following command: ```shell cdc cli changefeed create --server=http://127.0.0.1:8300 --sink-uri="mysql://root:123456@127.0.0.1:3306/" --changefeed-id="simple-replication-task" @@ -239,6 +282,6 @@ For more command usage methods and details, see [Manage Changefeeds](/ticdc/ticd ## Monitoring -Currently, the monitoring dashboard **TiCDC-New-Arch** for the TiCDC new architecture is not managed by TiUP yet. To view this dashboard on Grafana, you need to manually import the [TiCDC monitoring metrics file](https://github.com/pingcap/ticdc/blob/master/metrics/grafana/ticdc_new_arch.json). +The monitoring dashboard for TiCDC in the new architecture is **TiCDC-New-Arch**. For TiDB clusters of v8.5.4 and later versions, this monitoring dashboard is integrated into Grafana during cluster deployment or upgrade, so no manual operation is required. If your cluster version is earlier than v8.5.4, you need to manually import the [TiCDC monitoring metrics file](https://github.com/pingcap/ticdc/blob/master/metrics/grafana/ticdc_new_arch.json) to enable monitoring. -For detailed descriptions of each monitoring metric, see [Metrics for TiCDC in the new architecture](/ticdc/monitor-ticdc.md#metrics-for-ticdc-in-the-new-architecture). \ No newline at end of file +For importing steps and detailed descriptions of each monitoring metric, see [Metrics for TiCDC in the new architecture](/ticdc/monitor-ticdc.md#metrics-for-ticdc-in-the-new-architecture). From 4c1bd1aa65a4c4c517f23564fd98e985cc39f9ad Mon Sep 17 00:00:00 2001 From: Grace Cai Date: Tue, 18 Nov 2025 17:11:11 +0800 Subject: [PATCH 11/12] Apply suggestions from code review --- ddl_embedded_analyze.md | 2 +- system-variables.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ddl_embedded_analyze.md b/ddl_embedded_analyze.md index d50c1fa12e707..3973bb167b60f 100644 --- a/ddl_embedded_analyze.md +++ b/ddl_embedded_analyze.md @@ -3,7 +3,7 @@ title: "`ANALYZE` Embedded in DDL Statements" summary: This document describes the `ANALYZE` feature embedded in DDL statements for newly created or reorganized indexes, which ensures that statistics for new indexes are updated promptly. --- -# `ANALYZE` Embedded in DDL Statements Introduced in v8.5.4 and v9.0.0 +# `ANALYZE` Embedded in DDL Statements New in v8.5.4 This document describes the `ANALYZE` feature embedded in the following two types of DDL statements: diff --git a/system-variables.md b/system-variables.md index 6a8a5fdd1def5..0d4fb3573afbb 100644 --- a/system-variables.md +++ b/system-variables.md @@ -1644,7 +1644,7 @@ mysql> SELECT job_info FROM mysql.analyze_jobs ORDER BY end_time DESC LIMIT 1; -### tidb_stats_update_during_ddl New in v8.5.4 and v9.0.0 +### tidb_stats_update_during_ddl New in v8.5.4 - Scope: GLOBAL - Persists to cluster: Yes From 69c3e3e172453fe130ad61966a506b0496b86466 Mon Sep 17 00:00:00 2001 From: Grace Cai Date: Tue, 18 Nov 2025 17:12:39 +0800 Subject: [PATCH 12/12] Apply suggestions from code review --- ddl_embedded_analyze.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddl_embedded_analyze.md b/ddl_embedded_analyze.md index 3973bb167b60f..4056c761bf3c4 100644 --- a/ddl_embedded_analyze.md +++ b/ddl_embedded_analyze.md @@ -3,7 +3,7 @@ title: "`ANALYZE` Embedded in DDL Statements" summary: This document describes the `ANALYZE` feature embedded in DDL statements for newly created or reorganized indexes, which ensures that statistics for new indexes are updated promptly. --- -# `ANALYZE` Embedded in DDL Statements New in v8.5.4 +# `ANALYZE` Embedded in DDL Statements Introduced in v8.5.4 This document describes the `ANALYZE` feature embedded in the following two types of DDL statements: