自增ID实现原理:
- 每个自增列使用一个全局可见的键值对用于记录当前已分配的最大ID;
- 为了降低分布式分配自增ID的网络开销,每个TiDB节点会缓存一个不重复的ID段;
- 当前预分配的ID段使用完毕,或者TIDB重启的时候就会重新申请新的ID段;
自增ID使用限制
- 必须在主键或者唯一索引列上
- 只能定义在类型为整型、FLOAT或者DOUBLE的列上
- 自增列不支持DEFAULT定义
- 不支持使用ALTER TABLE增加AUTO_INCREMENT属性
- 默认不允许移除AUTO_INCREMENT属性,可以通过@@tidb_allow_remove_auto_inc来控制是否允许删除自增属性;
- 可以保证自增不唯一,无法保证顺序
AUTO_RANDOM用于解决聚簇表大批量写入数据时,因含有整型自增主键而产生的热点问题
mysql> create table t(a bigint primary key auto_random);
Query OK, 0 rows affected, 1 warning (0.28 sec)
mysql> insert into t values(),(),(),();
Query OK, 4 rows affected (0.05 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from t;
+---------------------+
| a |
+---------------------+
| 1441151880758558725 |
| 1441151880758558726 |
| 4899916394579099655 |
| 4899916394579099656 |
| 6052837899185946625 |
| 6052837899185946626 |
| 6052837899185946627 |
| 6052837899185946628 |
| 6341068275337658377 |
| 6341068275337658378 |
+---------------------+
10 rows in set (0.00 sec)
当tidb_enable_clustered_index值为默认值INT_ONLY时,所见的auto_random的表为聚簇表
mysql> select @@global.tidb_enable_clustered_index;
+--------------------------------------+
| @@global.tidb_enable_clustered_index |
+--------------------------------------+
| INT_ONLY |
+--------------------------------------+
1 row in set (0.00 sec)
mysql> show create table t\G
*************************** 1. row ***************************
Table: t
Create Table: CREATE TABLE `t` (
`a` bigint(20) NOT NULL /*T![auto_rand] AUTO_RANDOM(5) */,
PRIMARY KEY (`a`) /*T![clustered_index] CLUSTERED */
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin /*T![auto_rand_base] AUTO_RANDOM_BASE=30001 */
1 row in set (0.00 sec)
系统变量 tidb_enable_clustered_index 默认值由 OFF 改成 INT_ONLY 且含义有如下变化:
-
ON:开启聚簇索引,支持添加或者删除非聚簇索引。
-
OFF:关闭聚簇索引,支持添加或者删除非聚簇索引。
-
INT_ONLY:默认值,行为与 v5.0 以下版本保持一致,与
alter-primary-key = false
一起使用可控制 INT 类型是否开启聚簇索引。
AUTO_RANDOM使用限制:
- AUTO_RANDOM列类型必须是BIGINT类型;
- 非聚簇表不支持AUTO_RANDOM;
- 不支持用ALTER TABLE 修改AUTO_RANDOM属性,包括添加或者移除该属性;
- 不支持修改AUTO_RANDOM属性的主键的列类型
- 不支持和AUTO_INCREMENT同时指定在一列上;
- 不支持和列的DEFAULT指定在一列上
- INSERT的时候不支持显示指定AUTO_RANDOM的值,这可能导致提前耗尽用于自动分配的数值
MySQL迁移TiDB注意事项
如果业务是从MySQL迁移至TiDB,尽量保持使用习惯上的一致性;
1, 建表的时候创建非聚簇表;如果创建聚簇表,会存在写热点的问题,使用AUTO_RANDOM又会改变主键自增ID的值;
2, 为表添加SHARD_ROW_ID_BITS 和 PRE_SPLIT_REGIONS表
3, 其他没有主键自增ID或者数据量和访问量小,不会造成热点的可以保持原有设计;
TiDB上新建的表
- 特别注意业务是否要求主键ID单调连续性
- 建表时优先创建聚簇表--查询时不需要回表
- 使用AUTO_RANDOM代替AUTO_INCREMENT创建主键
- 准确地选择列的数据类型,优先用整型或者日期,尽量避免字符串;
- 避免创建无效索引