AutoRandom 是 TiDB 4.0 提供的一种扩展语法,用于解决整数类型主键通过 AutoIncrement 属性隐式分配 ID 时的写热点问题。
在前面的章节提到过,TiDB 的每一行数据都包含一个隐式的 _tidb_rowid
。_tidb_rowid
会被编码到存储引擎的 Key 上,在 TiKV 中,这决定了数据在 TiKV 中的 Region 位置。
如果表的主键为整数类型,则 TiDB 会把表的主键映射为 _tidb_rowid
,即使用“主键聚簇索引”。在这种情况下,如果表使用了 AUTO_INCREMENT
就会造成主键的热点问题,并无法使用 SHARD_ROW_ID_BITS
来打散热点。
针对上述热点问题,如果使用 AUTO_INCREMENT
仅仅只是用来保证主键唯一性(不需要连续或递增),那么我们可以将 AUTO_INCREMENT
改为 AUTO_RANDOM
,插入数据时让 TiDB 自动为整型主键列分配一个值,消除行 ID 的连续性,从而达到打散热点的目的。
AutoRandom 提供以下的功能:
- 唯一性:TiDB 始终保持填充数据在表范围内的唯一性。
- 高性能:TiDB 能够以较高的吞吐分配数据,并保证数据的随机分布以配合
PRE_SPLIT_REGION
语法共同使用,避免大量写入时的写热点问题。 - 支持隐式分配和显式写入:类似列的 AutoIncrement 属性,列的值既可以由 TiDB Server 自动分配,也可以由客户端直接指定写入。该需求来自于使用 Binlog 进行集群间同步时,保证上下游数据始终一致。
在建表时,AUTO_RANDOM
关键字可以作为列属性,指定在 TiDB 主键列上。TiDB 4.0 中,列属性语法定义被更新为:
column_definition:
data_type [NOT NULL | NULL] [DEFAULT default_value]
[AUTO_INCREMENT | AUTO_RANDOM [(length)]]
[UNIQUE [KEY] | [PRIMARY] KEY]
[COMMENT 'string']
[reference_definition]
注意,AutoRandom 仅支持主键列,唯一索引列尚不支持,目前也没有支持计划。AUTO_RANDOM
关键字后可以指定 Shard Bits 数量,默认为 5。
使用 AUTO_RANDOM 功能前,须在 TiDB 配置文件 experimental
部分设置 allow-auto-random = true
。该参数详情可参见 allow-auto-random。
以下面语句建立的表为例:
tidb> create table t (a int primary key auto_random);
此时再执行形如 INSERT INTO t(b) values... 的 INSERT 语句,示例如下:
tidb> insert into t values (), ();
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
tidb> select * from t;
+-----------+
| a |
+-----------+
| 201326593 |
| 201326594 |
+-----------+
2 rows in set (0.00 sec)
tidb> insert into t values (), ();
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
tidb> select * from t;
+------------+
| a |
+------------+
| 201326593 |
| 201326594 |
| 2080374787 |
| 2080374788 |
+------------+
4 rows in set (0.00 sec)
tidb> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
| 2080374787 |
+------------------+
1 row in set (0.00 sec)
注意:
- 如果该 INSERT 语句没有指定整型主键列(a 列)的值,TiDB 会为该列自动分配值。该值不保证自增,不保证连续,只保证唯一,避免了连续的行 ID 带来的热点问题。
- 如果该 INSERT 语句显式指定了整型主键列的值,和 AutoIncrement 属性类似,TiDB 会保存该值。
- 若在单条 INSERT 语句中写入多个值,AutoRandom 属性会保证分配 ID 的连续性,同时
LAST_INSERT_ID()
返回第一个分配的值,这使得可以通过LAST_INSERT_ID()
结果推断出所有被分配的 ID。
与 AutoRandom 相比,TiDB 还可以通过其他的方式避免主键自动分配时的写热点问题:
-
使用 alter-primary-key 配置选项关闭主键聚簇索引,使用 AutoIncrement +
SHARD_ROW_ID_BITS
。在这种方式下,主键索引被当做普通的唯一索引处理,使得数据的写入可以由
SHARD_ROW_ID_BITS
语法打散避免热点,但缺点在于,主键仍然存在索引写入的热点,同时在查询时,由于关闭了聚簇索引,针对主键的查询需要进行一次额外的回表。 -
在主键指定
UUID()
函数。这种做法同样可以为主键自动分配随机的默认值,保证数据和主键不存在写热点问题。但缺点在于
UUID()
分配的是字符串类型。TiDB 不支持字符串类型主键的聚簇索引,同样带来主键查询的额外回表。
参考文献: