_tidb_rowid
_tidb_rowid 是 TiDB 自动生成的一个隐藏系统列,在没有使用聚簇索引的表中作为表的内部行 ID。你无法在表结构中定义或修改此列,但当表使用 _tidb_rowid 作为其内部行 ID 时,可以在 SQL 语句中引用它。
在当前实现中,_tidb_rowid 是一个由 TiDB 自动维护的 BIGINT NOT NULL 列。
_tidb_rowid 何时可用
当表没有使用聚簇主键作为行的唯一标识时,TiDB 会使用 _tidb_rowid 来标识每一行。实际上,这意味着以下表类型会使用 _tidb_rowid:
- 没有主键的表
- 主键显式定义为
NONCLUSTERED的表
_tidb_rowid 不适用于使用聚簇索引的表,即主键定义为 CLUSTERED 的表(无论是单列主键还是复合主键)。
以下示例显示了区别:
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,因为这两个表没有使用聚簇索引作为行标识:
SELECT _tidb_rowid, a, b FROM t1;
SELECT _tidb_rowid, id, a FROM t2;
对于 t3,_tidb_rowid 不可用,因为该表使用了聚簇索引作为行标识,:
SELECT _tidb_rowid, id, a FROM t3;
ERROR 1054 (42S22): Unknown column '_tidb_rowid' in 'field list'
读取 _tidb_rowid
对于使用了 _tidb_rowid 的表,你可以在 SELECT 语句中查询 _tidb_rowid。这对于分页查询、故障排除和批量处理等任务非常有用。
示例:
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;
+-------------+---+---+
| _tidb_rowid | a | b |
+-------------+---+---+
| 1 | 1 | x |
| 2 | 2 | y |
+-------------+---+---+
要查看 TiDB 将要分配的下一个行 ID 值,请使用 SHOW TABLE ... NEXT_ROW_ID:
SHOW TABLE t NEXT_ROW_ID;
+-----------------------+------------+-------------+--------------------+-------------+
| 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。
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:
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;
+-------------+---+---+
| _tidb_rowid | a | b |
+-------------+---+---+
| 100 | 3 | z |
+-------------+---+---+
限制
- 不能创建名为
_tidb_rowid的用户列。 - 不能将现有用户列重命名为
_tidb_rowid。 _tidb_rowid是 TiDB 内部列,不适合作为业务主键或长期标识。- 在分区的非聚簇表上,
_tidb_rowid的值不保证在分区之间是唯一的。执行EXCHANGE PARTITION后,不同分区可能包含具有相同_tidb_rowid值的行。 _tidb_rowid是否存在取决于表结构。对于使用聚簇索引的表,应使用主键作为行标识。
解决热点问题
对于使用 _tidb_rowid 的表,TiDB 默认按递增顺序分配行 ID。在写密集型工作负载下,这可能会导致写热点。
要缓解此问题(针对依赖 _tidb_rowid 作为行 ID 的表),请考虑使用 SHARD_ROW_ID_BITS将行 ID 打散分布,并在需要时使用 PRE_SPLIT_REGIONS 提前分裂 Region。
示例:
CREATE TABLE t (
id BIGINT PRIMARY KEY NONCLUSTERED,
c INT
) SHARD_ROW_ID_BITS = 4;
SHARD_ROW_ID_BITS 仅适用于使用 _tidb_rowid 的表,不适用于聚簇索引表。
相关语句和变量
SHOW TABLE NEXT_ROW_ID:显示 TiDB 将要分配的下一个行 IDSHARD_ROW_ID_BITS:分片隐式行 ID 以减少热点Clustered Indexes:解释了何时表使用主键而不是_tidb_rowidtidb_opt_write_row_id:控制是否允许写入_tidb_rowid