From e14b958e2041d3be3b00fddacaa2dd57f2d5ed22 Mon Sep 17 00:00:00 2001 From: xixirangrang Date: Thu, 19 Mar 2026 13:31:40 +0800 Subject: [PATCH 1/9] Add temp.md --- temp.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 temp.md diff --git a/temp.md b/temp.md new file mode 100644 index 000000000000..af27ff4986a7 --- /dev/null +++ b/temp.md @@ -0,0 +1 @@ +This is a test file. \ No newline at end of file From 27d5651f3772fd87718cd46c4f1f466a3477c356 Mon Sep 17 00:00:00 2001 From: xixirangrang Date: Thu, 19 Mar 2026 13:31:45 +0800 Subject: [PATCH 2/9] Delete temp.md --- temp.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 temp.md diff --git a/temp.md b/temp.md deleted file mode 100644 index af27ff4986a7..000000000000 --- a/temp.md +++ /dev/null @@ -1 +0,0 @@ -This is a test file. \ No newline at end of file From 45eafc06aba5a46ce3d20c9127774e10dce6d791 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 19 Mar 2026 05:32:58 +0000 Subject: [PATCH 3/9] Auto-sync: Update Chinese docs from English PR Synced from: https://github.com/pingcap/docs/pull/22572 Target PR: https://github.com/pingcap/docs-cn/pull/21446 AI Provider: gemini Co-authored-by: github-actions[bot] --- TOC.md | 1 + clustered-indexes.md | 2 +- shard-row-id-bits.md | 7 +- .../sql-statement-show-table-next-rowid.md | 4 +- tidb-rowid.md | 160 ++++++++++++++++++ 5 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 tidb-rowid.md diff --git a/TOC.md b/TOC.md index a76d8dd8c0a2..0f4e27c25b0e 100644 --- a/TOC.md +++ b/TOC.md @@ -642,6 +642,7 @@ - 属性 - [AUTO_INCREMENT](/auto-increment.md) - [AUTO_RANDOM](/auto-random.md) + - [_tidb_rowid](/tidb-rowid.md) - [SHARD_ROW_ID_BITS](/shard-row-id-bits.md) - [字面值](/literal-values.md) - [Schema 对象名](/schema-object-names.md) diff --git a/clustered-indexes.md b/clustered-indexes.md index f42248f79667..76b74332ca6e 100644 --- a/clustered-indexes.md +++ b/clustered-indexes.md @@ -9,7 +9,7 @@ summary: 本文档介绍了聚簇索引的概念、使用场景、使用方法 目前 TiDB 中含有主键的表分为以下两类: -- `NONCLUSTERED`,表示该表的主键为非聚簇索引。在非聚簇索引表中,行数据的键由 TiDB 内部隐式分配的 `_tidb_rowid` 构成,而主键本质上是唯一索引,因此非聚簇索引表存储一行至少需要两个键值对,分别为 +- `NONCLUSTERED`,表示该表的主键为非聚簇索引。在非聚簇索引表中,行数据的键由 TiDB 内部隐式分配的 `_tidb_rowid` 值构成,而主键本质上是唯一索引,因此非聚簇索引表存储一行至少需要两个键值对,分别为 - `_tidb_rowid`(键)- 行数据(值) - 主键列数据(键) - `_tidb_rowid`(值) - `CLUSTERED`,表示该表的主键为聚簇索引。在聚簇索引表中,行数据的键由用户给定的主键列数据构成,因此聚簇索引表存储一行至少只要一个键值对,即 diff --git a/shard-row-id-bits.md b/shard-row-id-bits.md index 70a83f4d6db3..39454b2ae4c1 100644 --- a/shard-row-id-bits.md +++ b/shard-row-id-bits.md @@ -5,11 +5,11 @@ summary: 介绍 TiDB 的 `SHARD_ROW_ID_BITS` 表属性。 # SHARD_ROW_ID_BITS -本文介绍表属性 `SHARD_ROW_ID_BITS`,它用来设置隐式 `_tidb_rowid` 分片数量的 bit 位数。 +本文介绍表属性 `SHARD_ROW_ID_BITS`,它用来设置隐式 [`_tidb_rowid`](/tidb-rowid.md) 分片数量的 bit 位数。 ## 基本概念 -对于非[聚簇索引](/clustered-indexes.md)主键或没有主键的表,TiDB 会使用一个隐式的自增 rowid。大量执行 `INSERT` 插入语句时会把数据集中写入单个 Region,造成写入热点。 +对于非聚簇索引主键或没有主键的表,TiDB 会使用隐藏的 [`_tidb_rowid`](/tidb-rowid.md) 作为隐式自增 rowid。大量执行 `INSERT` 插入语句时会把数据集中写入单个 Region,造成写入热点。 通过设置 `SHARD_ROW_ID_BITS`,可以把 rowid 打散写入多个不同的 Region,缓解写入热点问题。 @@ -23,8 +23,9 @@ summary: 介绍 TiDB 的 `SHARD_ROW_ID_BITS` 表属性。 |--------|--------|--------------| | 1 bit | `S` bits | `63-S` bits | -- 自增位的值保存在 TiKV 中,由 TiDB 按顺序分配,每次分配后值会自增 1。自增位确保了 `_tidb_rowid` 列的值全局唯一。当自增位的值耗尽后(即达到最大值时),再次自动分配时会报 `Failed to read auto-increment value from storage engine` 错误。 +- 自增位的值保存在 TiKV 中,由 TiDB 按顺序分配,每次分配后值会自增 1。当自增位的值耗尽后(即达到最大值时),再次自动分配时会报 `Failed to read auto-increment value from storage engine` 错误。 - 关于 `_tidb_rowid` 取值范围:最终生成值包含的最大位数 = 分片位 + 自增位,最大值为 `(2^63)-1`。 +> `_tidb_rowid` 是内部行句柄。不要假定它在所有情况下都是全局唯一的。对于未使用聚簇索引的分区表,`ALTER TABLE ... EXCHANGE PARTITION` 操作可能会导致不同分区具有相同的 `_tidb_rowid` 值。详情请参阅 [`_tidb_rowid`](/tidb-rowid.md)。 > **注意:** > diff --git a/sql-statements/sql-statement-show-table-next-rowid.md b/sql-statements/sql-statement-show-table-next-rowid.md index 2f0869eec8e2..cffbb2bf0125 100644 --- a/sql-statements/sql-statement-show-table-next-rowid.md +++ b/sql-statements/sql-statement-show-table-next-rowid.md @@ -7,7 +7,7 @@ summary: TiDB 数据库中 SHOW TABLE NEXT_ROW_ID 的使用概况。 `SHOW TABLE NEXT_ROW_ID` 语句用于显示用户表中某些特殊列的详情,主要包含以下几种类型: -* TiDB 创建的 [`AUTO_INCREMENT`](/auto-increment.md) 类型列,即 `_tidb_rowid` 列 +* TiDB 自动管理的隐藏行句柄列 `_tidb_rowid`(`_tidb_rowid`) * 用户创建的 `AUTO_INCREMENT` 类型列 * 用户创建的 [`AUTO_RANDOM`](/auto-random.md) 类型列 * 用户创建的 [`SEQUENCE`](/sql-statements/sql-statement-create-sequence.md) 对象信息 @@ -69,3 +69,5 @@ SHOW TABLE t NEXT_ROW_ID; * [CREATE TABLE](/sql-statements/sql-statement-create-table.md) * [AUTO_RANDOM](/auto-random.md) * [CREATE_SEQUENCE](/sql-statements/sql-statement-create-sequence.md) +* [_tidb_rowid](/tidb-rowid.md) + diff --git a/tidb-rowid.md b/tidb-rowid.md new file mode 100644 index 000000000000..4d3b640055c2 --- /dev/null +++ b/tidb-rowid.md @@ -0,0 +1,160 @@ +--- +title: _tidb_rowid +summary: 了解 `_tidb_rowid` 是什么,何时可用,以及如何安全地使用它。 +--- + +# _tidb_rowid + +`_tidb_rowid` 是一个 TiDB 使用的隐藏系统列,作为不使用聚集索引的表的行句柄。你不会在表模式中声明此列,但当表使用 `_tidb_rowid` 作为其句柄时,你可以在 SQL 中引用它。 + +在当前实现中,`_tidb_rowid` 是一个由 TiDB 管理的额外的 `BIGINT NOT NULL` 句柄列。 + +> **警告:** +> +> - 在所有情况下,都不要假定 `_tidb_rowid` 是全局唯一的。对于不使用聚集索引的分区表,`ALTER TABLE ... EXCHANGE PARTITION` 可能会导致不同分区具有相同的 `_tidb_rowid` 值。 +> - 如果你需要一个稳定的唯一标识符,请定义并使用显式主键,而不是依赖 `_tidb_rowid`。 + +## `_tidb_rowid` 何时可用 + +`_tidb_rowid` 可用于其行句柄不是聚集主键的表。实际上,这意味着以下表类型会使用 `_tidb_rowid`: + +- 没有主键的表 +- 主键明确定义为 `NONCLUSTERED` 的表 + +`_tidb_rowid` 不适用于使用聚集索引的表,包括以下情况: + +- 主键为整数且作为聚集行句柄的表 +- 在复合主键上具有聚集索引的表 + +以下示例显示了区别: + +```sql +CREATE TABLE t1 (a INT, b VARCHAR(20)); +CREATE TABLE t2 (id BIGINT PRIMARY KEY NONCLUSTERED, a INT); +CREATE TABLE t3 (id BIGINT PRIMARY KEY CLUSTERED, a INT); +``` + +对于 `t1` 和 `t2`,你可以查询 `_tidb_rowid`: + +```sql +SELECT _tidb_rowid, a, b FROM t1; +SELECT _tidb_rowid, id, a FROM t2; +``` + +对于 `t3`,`_tidb_rowid` 不可用,因为聚集主键已经是行句柄: + +```sql +SELECT _tidb_rowid, id, a FROM t3; +``` + +```sql +ERROR 1054 (42S22): Unknown column '_tidb_rowid' in 'field list' +``` + +## 读取 `_tidb_rowid` + +对于支持的表,你可以在 `SELECT` 语句中使用 `_tidb_rowid`。这对于分页、故障排除和批量处理等任务非常有用。 + +示例: + +```sql +CREATE TABLE t (a INT, b VARCHAR(20)); +INSERT INTO t VALUES (1, 'x'), (2, 'y'); + +SELECT _tidb_rowid, a, b FROM t ORDER BY _tidb_rowid; +``` + +```sql ++-------------+---+---+ +| _tidb_rowid | a | b | ++-------------+---+---+ +| 1 | 1 | x | +| 2 | 2 | y | ++-------------+---+---+ +``` + +要检查 TiDB 将要分配的下一个行 ID 值,请使用 `SHOW TABLE ... NEXT_ROW_ID`: + +```sql +SHOW TABLE t NEXT_ROW_ID; +``` + +```sql ++-----------------------+------------+-------------+--------------------+-------------+ +| DB_NAME | TABLE_NAME | COLUMN_NAME | NEXT_GLOBAL_ROW_ID | ID_TYPE | ++-----------------------+------------+-------------+--------------------+-------------+ +| update_doc_rowid_test | t | _tidb_rowid | 30001 | _TIDB_ROWID | ++-----------------------+------------+-------------+--------------------+-------------+ +``` + +## 写入 `_tidb_rowid` + +默认情况下,TiDB 不允许 `INSERT`、`REPLACE` 或 `UPDATE` 语句直接写入 `_tidb_rowid`。 + +```sql +INSERT INTO t(_tidb_rowid, a, b) VALUES (101, 4, 'w'); +``` + +```sql +ERROR 1105 (HY000): insert, update and replace statements for _tidb_rowid are not supported +``` + +如果你需要在数据导入或迁移期间保留行 ID,请先启用系统变量 [`tidb_opt_write_row_id`](/system-variables.md#tidb_opt_write_row_id): + +```sql +SET @@tidb_opt_write_row_id = ON; +INSERT INTO t(_tidb_rowid, a, b) VALUES (100, 3, 'z'); +SET @@tidb_opt_write_row_id = OFF; + +SELECT _tidb_rowid, a, b FROM t WHERE _tidb_rowid = 100; +``` + +```sql ++-------------+---+---+ +| _tidb_rowid | a | b | ++-------------+---+---+ +| 100 | 3 | z | ++-------------+---+---+ +``` + +> **警告:** +> +> `tidb_opt_write_row_id` 仅用于导入和迁移场景。不推荐用于常规应用程序写入。 + +## 限制 + +- 你不能创建名为 `_tidb_rowid` 的用户列。 +- 你不能将现有用户列重命名为 `_tidb_rowid`。 +- `_tidb_rowid` 是一个内部行句柄。不要将其视为长期业务键。 +- 在分区的非聚集表上,`_tidb_rowid` 的值不保证在分区之间是唯一的。执行 `EXCHANGE PARTITION` 后,不同分区可能包含具有相同 `_tidb_rowid` 值的行。 +- `_tidb_rowid` 是否存在取决于表布局。如果表使用聚集索引,请改用主键。 + +## 热点考虑 + +对于使用 `_tidb_rowid` 的表,TiDB 默认按递增顺序分配行 ID。在写密集型工作负载下,这可能会导致写热点。 + +要缓解此问题(针对依赖隐式行 ID 的表),请考虑使用 [`SHARD_ROW_ID_BITS`](/shard-row-id-bits.md),并在需要时使用 [`PRE_SPLIT_REGIONS`](/sql-statements/sql-statement-split-region.md#pre_split_regions)。 + +示例: + +```sql +CREATE TABLE t ( + id BIGINT PRIMARY KEY NONCLUSTERED, + c INT +) SHARD_ROW_ID_BITS = 4; +``` + +`SHARD_ROW_ID_BITS` 仅适用于使用隐式行 ID 路径的表。它不适用于聚集索引表。 + +## 相关语句和变量 + +- [`SHOW TABLE NEXT_ROW_ID`](/sql-statements/sql-statement-show-table-next-rowid.md):显示 TiDB 将要分配的下一个行 ID +- [`SHARD_ROW_ID_BITS`](/shard-row-id-bits.md):分片隐式行 ID 以减少热点 +- [`Clustered Indexes`](/clustered-indexes.md):解释了何时表使用主键而不是 `_tidb_rowid` +- [`tidb_opt_write_row_id`](/system-variables.md#tidb_opt_write_row_id):控制是否允许写入 `_tidb_rowid` + +## 另请参阅 + +- [CREATE TABLE](/sql-statements/sql-statement-create-table.md) +- [AUTO_INCREMENT](/auto-increment.md) +- [Non-transactional DML](/non-transactional-dml.md) \ No newline at end of file From 6194b3539f593f41019e127eb2788f3022cba473 Mon Sep 17 00:00:00 2001 From: xixirangrang Date: Thu, 19 Mar 2026 13:57:22 +0800 Subject: [PATCH 4/9] Apply suggestions from code review --- clustered-indexes.md | 2 +- shard-row-id-bits.md | 3 ++ .../sql-statement-show-table-next-rowid.md | 3 +- tidb-rowid.md | 32 +++++++++---------- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/clustered-indexes.md b/clustered-indexes.md index 76b74332ca6e..d452656eb9ca 100644 --- a/clustered-indexes.md +++ b/clustered-indexes.md @@ -9,7 +9,7 @@ summary: 本文档介绍了聚簇索引的概念、使用场景、使用方法 目前 TiDB 中含有主键的表分为以下两类: -- `NONCLUSTERED`,表示该表的主键为非聚簇索引。在非聚簇索引表中,行数据的键由 TiDB 内部隐式分配的 `_tidb_rowid` 值构成,而主键本质上是唯一索引,因此非聚簇索引表存储一行至少需要两个键值对,分别为 +- `NONCLUSTERED`,表示该表的主键为非聚簇索引。在非聚簇索引表中,行数据的键由 TiDB 内部隐式分配的 [`_tidb_rowid`](/tidb-rowid.md) 值构成,而主键本质上是唯一索引,因此非聚簇索引表存储一行至少需要两个键值对,分别为 - `_tidb_rowid`(键)- 行数据(值) - 主键列数据(键) - `_tidb_rowid`(值) - `CLUSTERED`,表示该表的主键为聚簇索引。在聚簇索引表中,行数据的键由用户给定的主键列数据构成,因此聚簇索引表存储一行至少只要一个键值对,即 diff --git a/shard-row-id-bits.md b/shard-row-id-bits.md index 39454b2ae4c1..2f20e5526573 100644 --- a/shard-row-id-bits.md +++ b/shard-row-id-bits.md @@ -25,6 +25,9 @@ summary: 介绍 TiDB 的 `SHARD_ROW_ID_BITS` 表属性。 - 自增位的值保存在 TiKV 中,由 TiDB 按顺序分配,每次分配后值会自增 1。当自增位的值耗尽后(即达到最大值时),再次自动分配时会报 `Failed to read auto-increment value from storage engine` 错误。 - 关于 `_tidb_rowid` 取值范围:最终生成值包含的最大位数 = 分片位 + 自增位,最大值为 `(2^63)-1`。 + +> **警告:** +> > `_tidb_rowid` 是内部行句柄。不要假定它在所有情况下都是全局唯一的。对于未使用聚簇索引的分区表,`ALTER TABLE ... EXCHANGE PARTITION` 操作可能会导致不同分区具有相同的 `_tidb_rowid` 值。详情请参阅 [`_tidb_rowid`](/tidb-rowid.md)。 > **注意:** diff --git a/sql-statements/sql-statement-show-table-next-rowid.md b/sql-statements/sql-statement-show-table-next-rowid.md index cffbb2bf0125..a259071eb551 100644 --- a/sql-statements/sql-statement-show-table-next-rowid.md +++ b/sql-statements/sql-statement-show-table-next-rowid.md @@ -7,7 +7,7 @@ summary: TiDB 数据库中 SHOW TABLE NEXT_ROW_ID 的使用概况。 `SHOW TABLE NEXT_ROW_ID` 语句用于显示用户表中某些特殊列的详情,主要包含以下几种类型: -* TiDB 自动管理的隐藏行句柄列 `_tidb_rowid`(`_tidb_rowid`) +* TiDB 自动管理的隐藏行句柄列 [`_tidb_rowid`](/tidb-rowid.md) * 用户创建的 `AUTO_INCREMENT` 类型列 * 用户创建的 [`AUTO_RANDOM`](/auto-random.md) 类型列 * 用户创建的 [`SEQUENCE`](/sql-statements/sql-statement-create-sequence.md) 对象信息 @@ -70,4 +70,3 @@ SHOW TABLE t NEXT_ROW_ID; * [AUTO_RANDOM](/auto-random.md) * [CREATE_SEQUENCE](/sql-statements/sql-statement-create-sequence.md) * [_tidb_rowid](/tidb-rowid.md) - diff --git a/tidb-rowid.md b/tidb-rowid.md index 4d3b640055c2..1bd0f08d51f6 100644 --- a/tidb-rowid.md +++ b/tidb-rowid.md @@ -5,26 +5,26 @@ summary: 了解 `_tidb_rowid` 是什么,何时可用,以及如何安全地 # _tidb_rowid -`_tidb_rowid` 是一个 TiDB 使用的隐藏系统列,作为不使用聚集索引的表的行句柄。你不会在表模式中声明此列,但当表使用 `_tidb_rowid` 作为其句柄时,你可以在 SQL 中引用它。 +`_tidb_rowid` 是一个 TiDB 使用的隐藏系统列,作为不使用聚集索引的表的行句柄。你不需要在表模式中声明此列,但当表使用 `_tidb_rowid` 作为其句柄时,你可以在 SQL 中引用它。 在当前实现中,`_tidb_rowid` 是一个由 TiDB 管理的额外的 `BIGINT NOT NULL` 句柄列。 > **警告:** > -> - 在所有情况下,都不要假定 `_tidb_rowid` 是全局唯一的。对于不使用聚集索引的分区表,`ALTER TABLE ... EXCHANGE PARTITION` 可能会导致不同分区具有相同的 `_tidb_rowid` 值。 -> - 如果你需要一个稳定的唯一标识符,请定义并使用显式主键,而不是依赖 `_tidb_rowid`。 +> - 在所有情况下,不要假定 `_tidb_rowid` 是全局唯一的。对于不使用聚集索引的分区表,执行 `ALTER TABLE ... EXCHANGE PARTITION` 可能会导致不同分区具有相同的 `_tidb_rowid` 值。 +> - 如果你需要一个稳定的唯一标识符,请定义并使用显式主键,而不是依赖 `_tidb_rowid`。 ## `_tidb_rowid` 何时可用 `_tidb_rowid` 可用于其行句柄不是聚集主键的表。实际上,这意味着以下表类型会使用 `_tidb_rowid`: -- 没有主键的表 -- 主键明确定义为 `NONCLUSTERED` 的表 +- 没有主键的表 +- 主键显式定义为 `NONCLUSTERED` 的表 `_tidb_rowid` 不适用于使用聚集索引的表,包括以下情况: -- 主键为整数且作为聚集行句柄的表 -- 在复合主键上具有聚集索引的表 +- 主键为整数且作为聚集行句柄的表 +- 在复合主键上具有聚集索引的表 以下示例显示了区别: @@ -123,13 +123,13 @@ SELECT _tidb_rowid, a, b FROM t WHERE _tidb_rowid = 100; ## 限制 -- 你不能创建名为 `_tidb_rowid` 的用户列。 -- 你不能将现有用户列重命名为 `_tidb_rowid`。 -- `_tidb_rowid` 是一个内部行句柄。不要将其视为长期业务键。 -- 在分区的非聚集表上,`_tidb_rowid` 的值不保证在分区之间是唯一的。执行 `EXCHANGE PARTITION` 后,不同分区可能包含具有相同 `_tidb_rowid` 值的行。 -- `_tidb_rowid` 是否存在取决于表布局。如果表使用聚集索引,请改用主键。 +- 不能创建名为 `_tidb_rowid` 的用户列。 +- 不能将现有用户列重命名为 `_tidb_rowid`。 +- `_tidb_rowid` 是一个内部行句柄。不要将其视为长期业务键。 +- 在分区的非聚集表上,`_tidb_rowid` 的值不保证在分区之间是唯一的。执行 `EXCHANGE PARTITION` 后,不同分区可能包含具有相同 `_tidb_rowid` 值的行。 +- `_tidb_rowid` 是否存在取决于表布局。如果表使用聚集索引,请改用主键。 -## 热点考虑 +## 关于热点的考虑 对于使用 `_tidb_rowid` 的表,TiDB 默认按递增顺序分配行 ID。在写密集型工作负载下,这可能会导致写热点。 @@ -155,6 +155,6 @@ CREATE TABLE t ( ## 另请参阅 -- [CREATE TABLE](/sql-statements/sql-statement-create-table.md) -- [AUTO_INCREMENT](/auto-increment.md) -- [Non-transactional DML](/non-transactional-dml.md) \ No newline at end of file +- [`CREATE TABLE`](/sql-statements/sql-statement-create-table.md) +- [`AUTO_INCREMENT`](/auto-increment.md) +- [Non-transactional DML](/non-transactional-dml.md) \ No newline at end of file From fafe37c4ff47b7c6d437b51f88ecd5ef664c0b59 Mon Sep 17 00:00:00 2001 From: xixirangrang Date: Thu, 19 Mar 2026 14:01:29 +0800 Subject: [PATCH 5/9] Update tidb-rowid.md --- tidb-rowid.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tidb-rowid.md b/tidb-rowid.md index 1bd0f08d51f6..a7ed48548f2d 100644 --- a/tidb-rowid.md +++ b/tidb-rowid.md @@ -148,10 +148,10 @@ CREATE TABLE t ( ## 相关语句和变量 -- [`SHOW TABLE NEXT_ROW_ID`](/sql-statements/sql-statement-show-table-next-rowid.md):显示 TiDB 将要分配的下一个行 ID -- [`SHARD_ROW_ID_BITS`](/shard-row-id-bits.md):分片隐式行 ID 以减少热点 -- [`Clustered Indexes`](/clustered-indexes.md):解释了何时表使用主键而不是 `_tidb_rowid` -- [`tidb_opt_write_row_id`](/system-variables.md#tidb_opt_write_row_id):控制是否允许写入 `_tidb_rowid` +- [`SHOW TABLE NEXT_ROW_ID`](/sql-statements/sql-statement-show-table-next-rowid.md):显示 TiDB 将要分配的下一个行 ID +- [`SHARD_ROW_ID_BITS`](/shard-row-id-bits.md):分片隐式行 ID 以减少热点 +- [`Clustered Indexes`](/clustered-indexes.md):解释了何时表使用主键而不是 `_tidb_rowid` +- [`tidb_opt_write_row_id`](/system-variables.md#tidb_opt_write_row_id):控制是否允许写入 `_tidb_rowid` ## 另请参阅 From 4cf590ae03231a340fc5ffddfb89d6cb7f3c0154 Mon Sep 17 00:00:00 2001 From: houfaxin Date: Thu, 19 Mar 2026 14:16:04 +0800 Subject: [PATCH 6/9] Update tidb-rowid.md --- tidb-rowid.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tidb-rowid.md b/tidb-rowid.md index a7ed48548f2d..d165e84a2a93 100644 --- a/tidb-rowid.md +++ b/tidb-rowid.md @@ -5,26 +5,26 @@ summary: 了解 `_tidb_rowid` 是什么,何时可用,以及如何安全地 # _tidb_rowid -`_tidb_rowid` 是一个 TiDB 使用的隐藏系统列,作为不使用聚集索引的表的行句柄。你不需要在表模式中声明此列,但当表使用 `_tidb_rowid` 作为其句柄时,你可以在 SQL 中引用它。 +`_tidb_rowid` 是一个 TiDB 使用的隐藏系统列,作为不使用聚簇索引的表的行句柄。你不需要在表模式中声明此列,但当表使用 `_tidb_rowid` 作为其句柄时,你可以在 SQL 中引用它。 在当前实现中,`_tidb_rowid` 是一个由 TiDB 管理的额外的 `BIGINT NOT NULL` 句柄列。 > **警告:** > -> - 在所有情况下,不要假定 `_tidb_rowid` 是全局唯一的。对于不使用聚集索引的分区表,执行 `ALTER TABLE ... EXCHANGE PARTITION` 可能会导致不同分区具有相同的 `_tidb_rowid` 值。 +> - 在所有情况下,不要假定 `_tidb_rowid` 是全局唯一的。对于不使用聚簇索引的分区表,执行 `ALTER TABLE ... EXCHANGE PARTITION` 可能会导致不同分区具有相同的 `_tidb_rowid` 值。 > - 如果你需要一个稳定的唯一标识符,请定义并使用显式主键,而不是依赖 `_tidb_rowid`。 ## `_tidb_rowid` 何时可用 -`_tidb_rowid` 可用于其行句柄不是聚集主键的表。实际上,这意味着以下表类型会使用 `_tidb_rowid`: +`_tidb_rowid` 可用于其行句柄不是聚簇主键的表。实际上,这意味着以下表类型会使用 `_tidb_rowid`: - 没有主键的表 - 主键显式定义为 `NONCLUSTERED` 的表 -`_tidb_rowid` 不适用于使用聚集索引的表,包括以下情况: +`_tidb_rowid` 不适用于使用聚簇索引的表,包括以下情况: -- 主键为整数且作为聚集行句柄的表 -- 在复合主键上具有聚集索引的表 +- 主键为整数且作为聚簇行句柄的表 +- 在复合主键上具有聚簇索引的表 以下示例显示了区别: @@ -41,7 +41,7 @@ SELECT _tidb_rowid, a, b FROM t1; SELECT _tidb_rowid, id, a FROM t2; ``` -对于 `t3`,`_tidb_rowid` 不可用,因为聚集主键已经是行句柄: +对于 `t3`,`_tidb_rowid` 不可用,因为聚簇主键已经是行句柄: ```sql SELECT _tidb_rowid, id, a FROM t3; @@ -126,8 +126,8 @@ SELECT _tidb_rowid, a, b FROM t WHERE _tidb_rowid = 100; - 不能创建名为 `_tidb_rowid` 的用户列。 - 不能将现有用户列重命名为 `_tidb_rowid`。 - `_tidb_rowid` 是一个内部行句柄。不要将其视为长期业务键。 -- 在分区的非聚集表上,`_tidb_rowid` 的值不保证在分区之间是唯一的。执行 `EXCHANGE PARTITION` 后,不同分区可能包含具有相同 `_tidb_rowid` 值的行。 -- `_tidb_rowid` 是否存在取决于表布局。如果表使用聚集索引,请改用主键。 +- 在分区的非聚簇表上,`_tidb_rowid` 的值不保证在分区之间是唯一的。执行 `EXCHANGE PARTITION` 后,不同分区可能包含具有相同 `_tidb_rowid` 值的行。 +- `_tidb_rowid` 是否存在取决于表布局。如果表使用聚簇索引,请改用主键。 ## 关于热点的考虑 @@ -144,7 +144,7 @@ CREATE TABLE t ( ) SHARD_ROW_ID_BITS = 4; ``` -`SHARD_ROW_ID_BITS` 仅适用于使用隐式行 ID 路径的表。它不适用于聚集索引表。 +`SHARD_ROW_ID_BITS` 仅适用于使用隐式行 ID 路径的表。它不适用于聚簇索引表。 ## 相关语句和变量 From 2fe0a752e63372555990b57f0187b5e6f9b8ca91 Mon Sep 17 00:00:00 2001 From: xixirangrang Date: Thu, 19 Mar 2026 15:03:46 +0800 Subject: [PATCH 7/9] Apply suggestions from code review Co-authored-by: tangenta --- tidb-rowid.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tidb-rowid.md b/tidb-rowid.md index d165e84a2a93..ed1efd41a6ff 100644 --- a/tidb-rowid.md +++ b/tidb-rowid.md @@ -5,7 +5,7 @@ summary: 了解 `_tidb_rowid` 是什么,何时可用,以及如何安全地 # _tidb_rowid -`_tidb_rowid` 是一个 TiDB 使用的隐藏系统列,作为不使用聚簇索引的表的行句柄。你不需要在表模式中声明此列,但当表使用 `_tidb_rowid` 作为其句柄时,你可以在 SQL 中引用它。 +`_tidb_rowid` 是一个 TiDB 使用的隐藏系统列,作为不使用聚簇索引的表的行句柄。你无法在表结构中定义此列,但当表使用 `_tidb_rowid` 作为其句柄时,你可以在 SQL 中引用它。 在当前实现中,`_tidb_rowid` 是一个由 TiDB 管理的额外的 `BIGINT NOT NULL` 句柄列。 @@ -127,7 +127,7 @@ SELECT _tidb_rowid, a, b FROM t WHERE _tidb_rowid = 100; - 不能将现有用户列重命名为 `_tidb_rowid`。 - `_tidb_rowid` 是一个内部行句柄。不要将其视为长期业务键。 - 在分区的非聚簇表上,`_tidb_rowid` 的值不保证在分区之间是唯一的。执行 `EXCHANGE PARTITION` 后,不同分区可能包含具有相同 `_tidb_rowid` 值的行。 -- `_tidb_rowid` 是否存在取决于表布局。如果表使用聚簇索引,请改用主键。 +- `_tidb_rowid` 是否存在取决于表结构。如果表使用聚簇索引,请改用主键。 ## 关于热点的考虑 @@ -144,7 +144,7 @@ CREATE TABLE t ( ) SHARD_ROW_ID_BITS = 4; ``` -`SHARD_ROW_ID_BITS` 仅适用于使用隐式行 ID 路径的表。它不适用于聚簇索引表。 +`SHARD_ROW_ID_BITS` 仅适用于使用隐式行 ID 的表。它不适用于聚簇索引表。 ## 相关语句和变量 From c1b6c45695d42d4afae7c3916a013fb3488fffdf Mon Sep 17 00:00:00 2001 From: xixirangrang Date: Mon, 23 Mar 2026 17:01:30 +0800 Subject: [PATCH 8/9] Update tidb-rowid.md --- tidb-rowid.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tidb-rowid.md b/tidb-rowid.md index ed1efd41a6ff..85c2119fe607 100644 --- a/tidb-rowid.md +++ b/tidb-rowid.md @@ -129,7 +129,7 @@ SELECT _tidb_rowid, a, b FROM t WHERE _tidb_rowid = 100; - 在分区的非聚簇表上,`_tidb_rowid` 的值不保证在分区之间是唯一的。执行 `EXCHANGE PARTITION` 后,不同分区可能包含具有相同 `_tidb_rowid` 值的行。 - `_tidb_rowid` 是否存在取决于表结构。如果表使用聚簇索引,请改用主键。 -## 关于热点的考虑 +## 解决热点问题 对于使用 `_tidb_rowid` 的表,TiDB 默认按递增顺序分配行 ID。在写密集型工作负载下,这可能会导致写热点。 From 8bb9c63fde44449f1a6da8d52c5f631b6f9cbcc6 Mon Sep 17 00:00:00 2001 From: xixirangrang Date: Fri, 27 Mar 2026 15:43:25 +0800 Subject: [PATCH 9/9] Apply suggestions from code review Co-authored-by: Grace Cai --- shard-row-id-bits.md | 4 +-- .../sql-statement-show-table-next-rowid.md | 2 +- tidb-rowid.md | 35 +++++++++---------- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/shard-row-id-bits.md b/shard-row-id-bits.md index 2f20e5526573..784faf037ab9 100644 --- a/shard-row-id-bits.md +++ b/shard-row-id-bits.md @@ -9,7 +9,7 @@ summary: 介绍 TiDB 的 `SHARD_ROW_ID_BITS` 表属性。 ## 基本概念 -对于非聚簇索引主键或没有主键的表,TiDB 会使用隐藏的 [`_tidb_rowid`](/tidb-rowid.md) 作为隐式自增 rowid。大量执行 `INSERT` 插入语句时会把数据集中写入单个 Region,造成写入热点。 +对于非聚簇索引主键或没有主键的表,TiDB 会使用内部自动生成的 [`_tidb_rowid`](/tidb-rowid.md) 作为隐式自增 rowid。大量执行 `INSERT` 插入语句时会把数据集中写入单个 Region,造成写入热点。 通过设置 `SHARD_ROW_ID_BITS`,可以把 rowid 打散写入多个不同的 Region,缓解写入热点问题。 @@ -28,7 +28,7 @@ summary: 介绍 TiDB 的 `SHARD_ROW_ID_BITS` 表属性。 > **警告:** > -> `_tidb_rowid` 是内部行句柄。不要假定它在所有情况下都是全局唯一的。对于未使用聚簇索引的分区表,`ALTER TABLE ... EXCHANGE PARTITION` 操作可能会导致不同分区具有相同的 `_tidb_rowid` 值。详情请参阅 [`_tidb_rowid`](/tidb-rowid.md)。 +> `_tidb_rowid` 是 TiDB 内部隐式分配的行 ID。不要假定它在所有情况下都是全局唯一的。对于未使用聚簇索引的分区表,`ALTER TABLE ... EXCHANGE PARTITION` 操作可能会导致不同分区具有相同的 `_tidb_rowid` 值。详情请参阅 [`_tidb_rowid`](/tidb-rowid.md)。 > **注意:** > diff --git a/sql-statements/sql-statement-show-table-next-rowid.md b/sql-statements/sql-statement-show-table-next-rowid.md index a259071eb551..818f362aae4a 100644 --- a/sql-statements/sql-statement-show-table-next-rowid.md +++ b/sql-statements/sql-statement-show-table-next-rowid.md @@ -7,7 +7,7 @@ summary: TiDB 数据库中 SHOW TABLE NEXT_ROW_ID 的使用概况。 `SHOW TABLE NEXT_ROW_ID` 语句用于显示用户表中某些特殊列的详情,主要包含以下几种类型: -* TiDB 自动管理的隐藏行句柄列 [`_tidb_rowid`](/tidb-rowid.md) +* TiDB 自动管理的隐藏行 ID 列 [`_tidb_rowid`](/tidb-rowid.md) * 用户创建的 `AUTO_INCREMENT` 类型列 * 用户创建的 [`AUTO_RANDOM`](/auto-random.md) 类型列 * 用户创建的 [`SEQUENCE`](/sql-statements/sql-statement-create-sequence.md) 对象信息 diff --git a/tidb-rowid.md b/tidb-rowid.md index 85c2119fe607..13b656fe76db 100644 --- a/tidb-rowid.md +++ b/tidb-rowid.md @@ -5,26 +5,23 @@ summary: 了解 `_tidb_rowid` 是什么,何时可用,以及如何安全地 # _tidb_rowid -`_tidb_rowid` 是一个 TiDB 使用的隐藏系统列,作为不使用聚簇索引的表的行句柄。你无法在表结构中定义此列,但当表使用 `_tidb_rowid` 作为其句柄时,你可以在 SQL 中引用它。 +`_tidb_rowid` 是 TiDB 自动生成的一个隐藏系统列,在没有使用聚簇索引的表中作为表的内部行 ID。你无法在表结构中定义或修改此列,但当表使用 `_tidb_rowid` 作为其内部行 ID 时,可以在 SQL 语句中引用它。 -在当前实现中,`_tidb_rowid` 是一个由 TiDB 管理的额外的 `BIGINT NOT NULL` 句柄列。 +在当前实现中,`_tidb_rowid` 是一个由 TiDB 自动维护的 `BIGINT NOT NULL` 列。 > **警告:** > -> - 在所有情况下,不要假定 `_tidb_rowid` 是全局唯一的。对于不使用聚簇索引的分区表,执行 `ALTER TABLE ... EXCHANGE PARTITION` 可能会导致不同分区具有相同的 `_tidb_rowid` 值。 +> - 不要假设 `_tidb_rowid` 在所有情况下都是全局唯一的。对于不使用聚簇索引的分区表,执行 `ALTER TABLE ... EXCHANGE PARTITION` 后,不同分区之间可能出现相同的 `_tidb_rowid`。 > - 如果你需要一个稳定的唯一标识符,请定义并使用显式主键,而不是依赖 `_tidb_rowid`。 ## `_tidb_rowid` 何时可用 -`_tidb_rowid` 可用于其行句柄不是聚簇主键的表。实际上,这意味着以下表类型会使用 `_tidb_rowid`: +当表没有使用聚簇主键作为行的唯一标识时,TiDB 会使用 `_tidb_rowid` 来标识每一行。实际上,这意味着以下表类型会使用 `_tidb_rowid`: - 没有主键的表 - 主键显式定义为 `NONCLUSTERED` 的表 -`_tidb_rowid` 不适用于使用聚簇索引的表,包括以下情况: - -- 主键为整数且作为聚簇行句柄的表 -- 在复合主键上具有聚簇索引的表 +`_tidb_rowid` 不适用于使用聚簇索引的表,即主键定义为 `CLUSTERED` 的表(无论是单列主键还是复合主键)。 以下示例显示了区别: @@ -34,14 +31,14 @@ CREATE TABLE t2 (id BIGINT PRIMARY KEY NONCLUSTERED, a INT); CREATE TABLE t3 (id BIGINT PRIMARY KEY CLUSTERED, a INT); ``` -对于 `t1` 和 `t2`,你可以查询 `_tidb_rowid`: +对于 `t1` 和 `t2`,你可以查询 `_tidb_rowid`,因为这两个表没有使用聚簇索引作为行标识: ```sql SELECT _tidb_rowid, a, b FROM t1; SELECT _tidb_rowid, id, a FROM t2; ``` -对于 `t3`,`_tidb_rowid` 不可用,因为聚簇主键已经是行句柄: +对于 `t3`,`_tidb_rowid` 不可用,因为该表使用了聚簇索引作为行标识,: ```sql SELECT _tidb_rowid, id, a FROM t3; @@ -53,7 +50,7 @@ ERROR 1054 (42S22): Unknown column '_tidb_rowid' in 'field list' ## 读取 `_tidb_rowid` -对于支持的表,你可以在 `SELECT` 语句中使用 `_tidb_rowid`。这对于分页、故障排除和批量处理等任务非常有用。 +对于使用了 `_tidb_rowid` 的表,你可以在 `SELECT` 语句中查询 `_tidb_rowid`。这对于分页查询、故障排除和批量处理等任务非常有用。 示例: @@ -73,7 +70,7 @@ SELECT _tidb_rowid, a, b FROM t ORDER BY _tidb_rowid; +-------------+---+---+ ``` -要检查 TiDB 将要分配的下一个行 ID 值,请使用 `SHOW TABLE ... NEXT_ROW_ID`: +要查看 TiDB 将要分配的下一个行 ID 值,请使用 `SHOW TABLE ... NEXT_ROW_ID`: ```sql SHOW TABLE t NEXT_ROW_ID; @@ -89,7 +86,7 @@ SHOW TABLE t NEXT_ROW_ID; ## 写入 `_tidb_rowid` -默认情况下,TiDB 不允许 `INSERT`、`REPLACE` 或 `UPDATE` 语句直接写入 `_tidb_rowid`。 +默认情况下,TiDB 不允许通过 `INSERT`、`REPLACE` 或 `UPDATE` 语句中直接写入 `_tidb_rowid`。 ```sql INSERT INTO t(_tidb_rowid, a, b) VALUES (101, 4, 'w'); @@ -99,7 +96,7 @@ INSERT INTO t(_tidb_rowid, a, b) VALUES (101, 4, 'w'); ERROR 1105 (HY000): insert, update and replace statements for _tidb_rowid are not supported ``` -如果你需要在数据导入或迁移期间保留行 ID,请先启用系统变量 [`tidb_opt_write_row_id`](/system-variables.md#tidb_opt_write_row_id): +在数据导入或迁移场景中,如需保留原始行 ID,请先启用系统变量 [`tidb_opt_write_row_id`](/system-variables.md#tidb_opt_write_row_id): ```sql SET @@tidb_opt_write_row_id = ON; @@ -125,15 +122,15 @@ SELECT _tidb_rowid, a, b FROM t WHERE _tidb_rowid = 100; - 不能创建名为 `_tidb_rowid` 的用户列。 - 不能将现有用户列重命名为 `_tidb_rowid`。 -- `_tidb_rowid` 是一个内部行句柄。不要将其视为长期业务键。 +- `_tidb_rowid` 是 TiDB 内部列,不适合作为业务主键或长期标识。 - 在分区的非聚簇表上,`_tidb_rowid` 的值不保证在分区之间是唯一的。执行 `EXCHANGE PARTITION` 后,不同分区可能包含具有相同 `_tidb_rowid` 值的行。 -- `_tidb_rowid` 是否存在取决于表结构。如果表使用聚簇索引,请改用主键。 +- `_tidb_rowid` 是否存在取决于表结构。对于使用聚簇索引的表,应使用主键作为行标识。 ## 解决热点问题 对于使用 `_tidb_rowid` 的表,TiDB 默认按递增顺序分配行 ID。在写密集型工作负载下,这可能会导致写热点。 -要缓解此问题(针对依赖隐式行 ID 的表),请考虑使用 [`SHARD_ROW_ID_BITS`](/shard-row-id-bits.md),并在需要时使用 [`PRE_SPLIT_REGIONS`](/sql-statements/sql-statement-split-region.md#pre_split_regions)。 +要缓解此问题(针对依赖 `_tidb_rowid` 作为行 ID 的表),请考虑使用 [`SHARD_ROW_ID_BITS`](/shard-row-id-bits.md)将行 ID 打散分布,并在需要时使用 [`PRE_SPLIT_REGIONS`](/sql-statements/sql-statement-split-region.md#pre_split_regions) 提前分裂 Region。 示例: @@ -144,7 +141,7 @@ CREATE TABLE t ( ) SHARD_ROW_ID_BITS = 4; ``` -`SHARD_ROW_ID_BITS` 仅适用于使用隐式行 ID 的表。它不适用于聚簇索引表。 +`SHARD_ROW_ID_BITS` 仅适用于使用 `_tidb_rowid` 的表,不适用于聚簇索引表。 ## 相关语句和变量 @@ -157,4 +154,4 @@ CREATE TABLE t ( - [`CREATE TABLE`](/sql-statements/sql-statement-create-table.md) - [`AUTO_INCREMENT`](/auto-increment.md) -- [Non-transactional DML](/non-transactional-dml.md) \ No newline at end of file +- [非事务 DML 语句](/non-transactional-dml.md) \ No newline at end of file