Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TiDB auto increment MySQL-compatible behavior clarification (#19861) #19965

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 34 additions & 10 deletions auto-increment.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,25 +390,49 @@ SELECT * FROM t;

## MySQL 兼容模式

从 v6.4.0 开始,TiDB 实现了中心化分配自增 ID 的服务,可以支持 TiDB 实例不缓存数据,而是每次请求都访问中心化服务获取 ID。
TiDB 提供了一种兼容 MySQL 的自增列模式,该模式能确保 ID 严格递增且间隙最小。要启用此模式,需在建表时将 `AUTO_ID_CACHE` 设置为 `1`:

当前中心化分配服务内置在 TiDB 进程,类似于 DDL Owner 的工作模式。有一个 TiDB 实例将充当“主”的角色提供 ID 分配服务,而其它的 TiDB 实例将充当“备”角色。当“主”节点发生故障时,会自动进行“主备切换”,从而保证中心化服务的高可用。
```sql
CREATE TABLE t(a int AUTO_INCREMENT key) AUTO_ID_CACHE 1;
```

当 `AUTO_ID_CACHE` 设置为 `1` 时,所有 TiDB 实例生成的 ID 严格全局递增,每个 ID 保证全局唯一,相较于默认缓存模式(`AUTO_ID_CACHE 0` 具有 30000 个缓存值),ID 间隙显著缩小。

MySQL 兼容模式的使用方式是,建表时将 `AUTO_ID_CACHE` 设置为 `1`
例如,启用 `AUTO_ID_CACHE 1` 后可以生成如下序列

```sql
CREATE TABLE t(a int AUTO_INCREMENT key) AUTO_ID_CACHE 1;
INSERT INTO t VALUES (); -- Returns ID 1
INSERT INTO t VALUES (); -- Returns ID 2
INSERT INTO t VALUES (); -- Returns ID 3
-- After failover
INSERT INTO t VALUES (); -- Might return ID 5
```

相比之下,使用默认缓存(`AUTO_ID_CACHE 0`)时可能出现较大间隙:

```sql
INSERT INTO t VALUES (); -- Returns ID 1
INSERT INTO t VALUES (); -- Returns ID 2
-- New TiDB instance allocates next batch
INSERT INTO t VALUES (); -- Returns ID 30001
```

尽管 `AUTO_ID_CACHE 1` 能保证 ID 严格递增且不会出现类似 `AUTO_ID_CACHE 0` 的大幅间隙,但在以下场景中仍可能出现微小间隙。这些间隙是维持 ID 全局唯一性和严格递增特性的必要代价:

- 主实例退出或崩溃的故障恢复期间

使用 MySQL 兼容模式后,能保证 ID **唯一**、**单调递增**,行为几乎跟 MySQL 完全一致。即使跨 TiDB 实例访问,ID 也不会出现回退。只有在中心化分配自增 ID 服务的“主” TiDB 实例进程退出(如该 TiDB 节点重启)或者异常崩溃时,才有可能造成部分 ID 不连续。这是因为主备切换时,“备” 节点需要丢弃一部分之前的“主” 节点已经分配的 ID,以保证 ID 不出现重复。

- TiDB 节点滚动升级期间
- 正常并发事务场景(与 MySQL 类似)

> **注意:**
>
> 在 TiDB 各个版本中,`AUTO_ID_CACHE` 设置为 `1` 都表明 TiDB 不再缓存 ID,但是不同版本的实现方式不一样
> `AUTO_ID_CACHE 1` 的行为和性能在不同 TiDB 版本中的演进如下
>
> - 对于 TiDB v6.4.0 之前的版本,由于每次分配 ID 都需要通过一个 TiKV 事务完成 `AUTO_INCREMENT` 值的持久化修改,因此设置 `AUTO_ID_CACHE` 为 `1` 会出现性能下降。
> - 对于 v6.4.0 及以上版本,由于引入了中心化的分配服务,`AUTO_INCREMENT` 值的修改只是在 TiDB 服务进程中的一个内存操作,相较于之前版本更快。
> - 将 `AUTO_ID_CACHE` 设置为 `0` 表示 TiDB 使用默认的缓存大小 `30000`。

使用 MySQL 兼容模式后,能保证 ID **唯一**、**单调递增**,行为几乎跟 MySQL 完全一致。即使跨 TiDB 实例访问,ID 也不会出现回退。只有在中心化分配自增 ID 服务的“主” TiDB 实例进程退出(如该 TiDB 节点重启)或者异常崩溃时,才有可能造成部分 ID 不连续。这是因为主备切换时,“备” 节点需要丢弃一部分之前的“主” 节点已经分配的 ID,以保证 ID 不出现重复。
> - v6.4.0 之前:每次 ID 分配需通过一个 TiKV 事务完成,会影响性能。
> - v6.4.0 起:引入集中式分配服务,ID 分配转为内存操作,性能显著提升。
> - v8.1.0 起:移除主节点退出时的自动 `forceRebase` 操作以实现快速重启。虽然故障恢复时可能产生额外非连续 ID,但可避免大量表使用 `AUTO_ID_CACHE 1` 时可能出现的写入阻塞。

## 使用限制

Expand Down