AUTO_RANDOM 从 v3.1.0 版本开始引入

使用场景

由于 AUTO_RANDOM 的值具有随机性和唯一性,因此 AUTO_RANDOM 通常用于代替 AUTO_INCREMENT,以避免 TiDB 分配连续的 ID 值造成单个存储节点的写热点问题。如果当前表的 AUTO_INCREMENT 列是主键列,且列类型为 BIGINT,可以通过 ALTER TABLE t MODIFY COLUMN id BIGINT AUTO_RANDOM(5);AUTO_INCREMENT 切换成 AUTO_RANDOM

关于如何在高并发写入场景下调优 TiDB,请参阅 TiDB 高并发写入场景最佳实践

基本概念

AUTO_RANDOM 是应用在 BIGINT 类型列的属性,用于列值的自动分配。其自动分配的值满足随机性唯一性

以下语句均可创建包含 AUTO_RANDOM 列的表,其中 AUTO_RANDOM 列必须被包含在主键中,并且是主键的第一列。

CREATE TABLE t (a BIGINT AUTO_RANDOM, b VARCHAR(255), PRIMARY KEY (a)); CREATE TABLE t (a BIGINT PRIMARY KEY AUTO_RANDOM, b VARCHAR(255)); CREATE TABLE t (a BIGINT AUTO_RANDOM(6), b VARCHAR(255), PRIMARY KEY (a)); CREATE TABLE t (a BIGINT AUTO_RANDOM(5, 54), b VARCHAR(255), PRIMARY KEY (a)); CREATE TABLE t (a BIGINT AUTO_RANDOM(5, 54), b VARCHAR(255), PRIMARY KEY (a, b));

AUTO_RANDOM 关键字可以被包裹在 TiDB 可执行注释中,注释语法请参考 TiDB 可执行注释

CREATE TABLE t (a bigint /*T![auto_rand] AUTO_RANDOM */, b VARCHAR(255), PRIMARY KEY (a)); CREATE TABLE t (a bigint PRIMARY KEY /*T![auto_rand] AUTO_RANDOM */, b VARCHAR(255)); CREATE TABLE t (a BIGINT /*T![auto_rand] AUTO_RANDOM(6) */, b VARCHAR(255), PRIMARY KEY (a)); CREATE TABLE t (a BIGINT /*T![auto_rand] AUTO_RANDOM(5, 54) */, b VARCHAR(255), PRIMARY KEY (a));

在用户执行 INSERT 语句时:

  • 如果语句中显式指定了 AUTO_RANDOM 列的值,则该值会被正常插入到表中。
  • 如果语句中没有显式指定 AUTO_RANDOM 列的值,TiDB 会自动生成一个随机的值插入到表中。
tidb> CREATE TABLE t (a BIGINT PRIMARY KEY AUTO_RANDOM, b VARCHAR(255)) /*T! PRE_SPLIT_REGIONS=2 */ ; Query OK, 0 rows affected, 1 warning (0.01 sec) tidb> INSERT INTO t(a, b) VALUES (1, 'string'); Query OK, 1 row affected (0.00 sec) tidb> SELECT * FROM t; +---+--------+ | a | b | +---+--------+ | 1 | string | +---+--------+ 1 row in set (0.01 sec) tidb> INSERT INTO t(b) VALUES ('string2'); Query OK, 1 row affected (0.00 sec) tidb> INSERT INTO t(b) VALUES ('string3'); Query OK, 1 row affected (0.00 sec) tidb> SELECT * FROM t; +---------------------+---------+ | a | b | +---------------------+---------+ | 1 | string | | 1152921504606846978 | string2 | | 4899916394579099651 | string3 | +---------------------+---------+ 3 rows in set (0.00 sec) tidb> SHOW CREATE TABLE t; +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | t | CREATE TABLE `t` ( `a` bigint(20) NOT NULL /*T![auto_rand] AUTO_RANDOM(5) */, `b` varchar(255) DEFAULT NULL, PRIMARY KEY (`a`) /*T![clustered_index] CLUSTERED */ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin /*T! PRE_SPLIT_REGIONS=2 */ | +-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) tidb> SHOW TABLE t REGIONS; +-----------+-----------------------------+-----------------------------+-----------+-----------------+---------------------+------------+---------------+------------+----------------------+------------------+------------------------+------------------+ | REGION_ID | START_KEY | END_KEY | LEADER_ID | LEADER_STORE_ID | PEERS | SCATTERING | WRITTEN_BYTES | READ_BYTES | APPROXIMATE_SIZE(MB) | APPROXIMATE_KEYS | SCHEDULING_CONSTRAINTS | SCHEDULING_STATE | +-----------+-----------------------------+-----------------------------+-----------+-----------------+---------------------+------------+---------------+------------+----------------------+------------------+------------------------+------------------+ | 62798 | t_158_ | t_158_r_2305843009213693952 | 62810 | 28 | 62811, 62812, 62810 | 0 | 151 | 0 | 1 | 0 | | | | 62802 | t_158_r_2305843009213693952 | t_158_r_4611686018427387904 | 62803 | 1 | 62803, 62804, 62805 | 0 | 39 | 0 | 1 | 0 | | | | 62806 | t_158_r_4611686018427387904 | t_158_r_6917529027641081856 | 62813 | 4 | 62813, 62814, 62815 | 0 | 160 | 0 | 1 | 0 | | | | 9289 | t_158_r_6917529027641081856 | 78000000 | 48268 | 1 | 48268, 58951, 62791 | 0 | 10628 | 43639 | 2 | 7999 | | | +-----------+-----------------------------+-----------------------------+-----------+-----------------+---------------------+------------+---------------+------------+----------------------+------------------+------------------------+------------------+ 4 rows in set (0.00 sec)

TiDB 自动分配的 AUTO_RANDOM(S, R) 列值共有 64 位:

  • S 表示分片位的数量,取值范围是 115。默认为 5
  • R 表示自动分配值域的总长度,取值范围是 3264。默认为 64

有符号位的 AUTO_RANDOM 列值的具体结构如下:

符号位保留位分片位自增位
1 bit64-R bitsS bitsR-1-S bits

无符号位的 AUTO_RANDOM 列值的具体结构如下:

保留位分片位自增位
64-R bitsS bitsR-S bits
  • 是否有符号位取决于该列是否存在 UNSIGNED 属性。
  • 保留位的长度为 64-R,保留位的内容始终为 0
  • 分片位的内容通过计算当前事务的开始时间的哈希值而得。要使用不同的分片位数量(例如 10),可以在建表时指定 AUTO_RANDOM(10)
  • 自增位的值保存在存储引擎中,按顺序分配,每次分配完值后会自增 1。自增位保证了 AUTO_RANDOM 列值全局唯一。当自增位耗尽后,再次自动分配时会报 Failed to read auto-increment value from storage engine 的错误。
  • 关于取值范围:最终生成值包含的最大位数 = 分片位 + 自增位。有符号位的列的取值范围是 [-(2^(R-1))+1, (2^(R-1))-1]。无符号位的列的取值范围是 [0, (2^R)-1]
  • AUTO_RANDOM 可以与 PRE_SPLIT_REGIONS 结合使用,用来在建表成功后就开始将表中的数据预均匀切分 2^(PRE_SPLIT_REGIONS) 个 Region。

AUTO RANDOM 列隐式分配的值会影响 last_insert_id()。可以使用 SELECT last_insert_id() 获取上一次 TiDB 隐式分配的 ID。

要查看某张含有 AUTO_RANDOM 属性的表的分片位数量,除了 SHOW CREATE TABLE 以外,还可以在系统表 INFORMATION_SCHEMA.TABLESTIDB_ROW_ID_SHARDING_INFO 一列中查到模式为 PK_AUTO_RANDOM_BITS=x 的值,其中 x 为分片位的数量。

创建完一张含有 AUTO_RANDOM 属性的表后,可以使用 SHOW WARNINGS 查看当前表可支持的最大隐式分配的次数:

CREATE TABLE t (a BIGINT AUTO_RANDOM, b VARCHAR(255), PRIMARY KEY (a)); SHOW WARNINGS;

输出结果如下:

+-------+------+---------------------------------------------------------+ | Level | Code | Message | +-------+------+---------------------------------------------------------+ | Note | 1105 | Available implicit allocation times: 288230376151711743 | +-------+------+---------------------------------------------------------+ 1 row in set (0.00 sec)

ID 隐式分配规则

AUTO_RANDOM 列隐式分配的值和自增列类似,也遵循 session 变量 auto_increment_incrementauto_increment_offset 的控制,其中隐式分配值的自增位 (ID) 满足等式 (ID - auto_increment_offset) % auto_increment_increment == 0

使用限制

目前在 TiDB 中使用 AUTO_RANDOM 有以下限制:

  • 要使用显式插入的功能,需要将系统变量 @@allow_auto_random_explicit_insert 的值设置为 1(默认值为 0)。不建议自行显式指定含有 AUTO_RANDOM 列的值。不恰当地显式赋值,可能会导致该表提前耗尽用于自动分配的数值。
  • 该属性必须指定在 BIGINT 类型的主键列上,否则会报错。此外,当主键属性为 NONCLUSTERED 时,即使是整型主键列,也不支持使用 AUTO_RANDOM。要了解关于 CLUSTERED 主键的详细信息,请参考聚簇索引
  • 不支持使用 ALTER TABLE 来修改 AUTO_RANDOM 属性,包括添加或移除该属性。
  • 支持将 AUTO_INCREMENT 属性改为 AUTO_RANDOM 属性。但在 AUTO_INCREMENT 的列数据最大值已接近 BIGINT 类型最大值的情况下,修改可能会失败。
  • 不支持修改含有 AUTO_RANDOM 属性的主键列的列类型。
  • 不支持与 AUTO_INCREMENT 同时指定在同一列上。
  • 不支持与列的默认值 DEFAULT 同时指定在同一列上。
  • AUTO_RANDOM 列的数据很难迁移到 AUTO_INCREMENT 列上,因为 AUTO_RANDOM 列自动分配的值通常都很大。

文档内容是否有帮助?