首批通过分布式安全可靠测评,为关键业务系统打造
说明
序列和自增列的区别:
- 创建序列时,默认为 NOORDER 属性(为了和 Oracle 行为兼容)。
- 创建自增列时,默认为 ORDER 属性(为了和 MySQL 行为兼容)。
更新时间:2026-07-28
在应用系统中,自增列和序列被广泛用于表数据的主键或序号,以实现数据的递增或唯一性。然而,在 OceanBase 数据库的分布式架构下,自增列和序列与传统集中式数据库存在显著差异。如果忽视这些差异,将导致不同的实现效果和性能。因此,本篇文档将帮助您深入了解 OceanBase 数据库自增列和序列的概念、实现方式、行为特性,并提供相应的使用建议。
自增列(AUTO_INCREMENT):数据库表中的一种列属性,可以自动生成唯一的、递增的值,用于表示该行数据的唯一标识。
序列(SEQUENCE):数据库按照一定规则生成的唯一且通常是递增的数值,通常被用于生成唯一标识符,独立于表存在。
OceanBase 数据库在不同版本中对自增列和序列功能进行了持续优化:
V3.2.1 版本:自增主键支持作为分区键,自增列的值全局唯一,但在分区内不保证始终增长,和原生 MySQL 行为不同。INSERT 均生成 distribute insert 计划,性能会有下降。
V4.0.0 版本:OceanBase 数据库的 MySQL 模式下,自增列支持指定两种不同的自增模式,您可以通过租户级配置项 DEFAULT_AUTO_INCREMENT_MODE 控制默认模式,也可在建表时指定 AUTO_INCREMENT_MODE。默认为 ORDER。
V4.2.2 版本:INTEGER 列类型增长支持 Online 方式。对于主键列、分区键、索引列、被生成列依赖的列和有 Check 约束的列,列类型如果为整型,当列类型修改为取值范围更大的整形列类型时(如 INT -> BIGINT),在 V4.2.1 版本中通过双表双写的 Offline DDL 实现,转换过程中会加表锁,阻塞读写。从 V4.2.2 版本开始,将 Offline DDL 改进为 Online DDL,整型列类型增长将不再影响业务写入。
V4.2.3 及以上版本:自增值起点支持改小。当减小一个表的自增字段的值时,如果表中已存在数据并且自增列中的最大值不小于新指定的 AUTO_INCREMENT 值时,新的 AUTO_INCREMENT 值将自动调整为表中自增列现有最大值的下一个取值。例如,自增列当前的最大值为 5,当前 AUTO_INCREMENT 的值是 8,而 AUTO_INCREMENT 设置为介于 0 到 6 之间的任何值,语句执行成功后,实际的 AUTO_INCREMENT 值都会被调整为 6。和原生 MySQL 行为兼容。
在 OceanBase 数据库 V4.2.3 版本中,您可以为每个表单独设置自增值缓存大小(CACHE SIZE)。在此版本之前,所有表的自增值缓存大小都由全局参数 AUTO_INCREMENT_CACHE_SIZE 控制,应用于每个节点。现在,您可以在创建表时,通过指定 AUTO_INCREMENT_CACHE_SIZE 参数,为不同的表设置不同的自增值缓存策略。
在 OceanBase 数据库 V4.2.3 版本中,ORDER 模式下,切主后不会跳变。
OceanBase 数据库的自增列支持两种模式,其核心区别在于缓存管理方式。
NOORDER 模式(分布式缓存):每个 OBServer 节点独立从内部表申请自增区间并缓存,性能高。缺点是不保证全局递增,易出现跳变。适用于对性能敏感或允许跳变的业务。
ORDER 模式(集中式缓存):选举一个 Leader OBServer 作为自增服务节点,其他节点通过 RPC 向其申请值。优点是在大多数情况下可生成连续递增的值,兼容 MySQL 行为。缺点是在高并发下性能低于 NOORDER,Leader 切换时仍可能跳变。在 V4.2.3 版本之后,ORDER 模式切主后不会跳变。
| 对比项 | 集中式数据库(MySQL) | OceanBase 数据库(分布式) |
|---|---|---|
| 自增连续性 | 强保证(单机) | 不强制保证,取决于模式 |
| 性能 | 高(本地缓存) | NOORDER 高,ORDER 稍低 |
| 容错性 | 单点风险 | 多副本容灾 |
| 跳变风险 | 低(仅重启) | 较高(多节点、切主) |
| 架构 | 单机缓存 | 分布式协调 |
OceanBase 数据库的用户中,许多业务最初运行在 DB2 或 Oracle 上,现计划转向 MySQL,需要将 DB2 或 Oracle 的业务迁移至 OceanBase 数据库 MySQL 模式的租户。为减少客户在迁移过程中对大量使用 SEQUENCE 的业务进行改造的复杂度,OceanBase 数据库在 MySQL 模式下提供了与 Oracle 行为兼容的 SEQUENCE 功能。
适用场景:
-- 创建表时定义自增列(默认 ORDER 模式)
CREATE TABLE t_user (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
) AUTO_INCREMENT = 1;
-- 显式指定 NOORDER 模式
CREATE TABLE t_order (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
order_no VARCHAR(20)
) AUTO_INCREMENT_MODE = 'NOORDER';
序列是独立于表的对象,可用于多表共享主键或复杂业务编号生成。
CREATE SEQUENCE seq_order_id
START WITH 1
INCREMENT BY 1
MINVALUE 1
MAXVALUE 9999999999
NOCYCLE
NOORDER
CACHE 100;
示例对比:
-- 创建一张含有自增列 id 的表,自增列(increment column)和表强绑定
obclient [test]> CREATE TABLE t1 (id bigint not null AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50));
obclient [test]> INSERT INTO t1 (name) VALUES ('A'),('B'),('C');
obclient [test]> SELECT * FROM t1;
+----+------+
| id | name |
+----+------+
| 1 | A |
| 2 | B |
| 3 | C |
+----+------+
3 rows in set (0.021 sec)
-- 创建一个序列,起始值是 1,最小值是 1,最大值是 5,步长是 2,序列的值不循环生成
obclient [test]> CREATE SEQUENCE seq1 START WITH 1 MINVALUE 1 MAXVALUE 5 INCREMENT BY 2 NOCYCLE;
obclient [test]> SELECT seq1.nextval FROM DUAL;
+---------+
| nextval |
+---------+
| 1 |
+---------+
1 row in set (0.012 sec)
obclient [test]> SELECT seq1.nextval FROM DUAL;
+---------+
| nextval |
+---------+
| 3 |
+---------+
1 row in set (0.004 sec)
obclient [test]> SELECT seq1.nextval FROM DUAL;
+---------+
| nextval |
+---------+
| 5 |
+---------+
1 row in set (0.004 sec)
-- 如果设置 NOCYCLE,达到 MAXVALUE 后,无法继续生成更大的序列
obclient [test]> SELECT seq1.nextval FROM DUAL;
ERROR 4332 (HY000): sequence exceeds MAXVALUE and cannot be instantiated
-- 再创建一个序列,起始值是 1,最小值是 1,最大值是 5,步长是 2,序列的值循环生成(在内存中预分配的自增值个数是 2)
obclient [test]> CREATE SEQUENCE seq7 START WITH 1 MINVALUE 1 MAXVALUE 5 INCREMENT BY 2 CYCLE CACHE 2;
obclient [test]> SELECT seq7.nextval FROM DUAL;
+---------+
| nextval |
+---------+
| 1 |
+---------+
1 row in set (0.009 sec)
obclient [test]> SELECT seq7.nextval FROM DUAL;
+---------+
| nextval |
+---------+
| 3 |
+---------+
1 row in set (0.005 sec)
obclient [test]> SELECT seq7.nextval FROM DUAL;
+---------+
| nextval |
+---------+
| 5 |
+---------+
1 row in set (0.005 sec)
obclient [test]> SELECT seq7.nextval FROM DUAL;
+---------+
| nextval |
+---------+
| 1 |
+---------+
1 row in set (0.001 sec)
-- 序列除了可用于顶层 SELECT,还可用在 INSERT 与 UPDATE 中
obclient [test]> CREATE TABLE t2 (c1 int);
obclient [test]> INSERT INTO t2 VALUES (seq7.nextval);
obclient [test]> SELECT * FROM t2;
+------+
| c1 |
+------+
| 3 |
+------+
1 row in set (0.001 sec)
obclient [test]> UPDATE t2 SET c1 = seq7.nextval;
obclient [test]> SELECT * FROM t2;
+------+
| c1 |
+------+
| 5 |
+------+
1 row in set (0.001 sec)
序列和自增列的区别:
由于 OceanBase 数据库是分布式数据库,自增机制在高可用切换、合并、宕机等场景下可能出现跳变(Gap),即自增值不连续。
假设 AUTO_INCREMENT_CACHE_SIZE 的值为 100,当分区表所在的节点 OBServer1、OBServer2 和 OBServer3 分别按以下顺序先后接收到 INSERT INTO VALUES (NULL) 的请求时,它们内部的处理逻辑如下:
此时表内插入数据的顺序为 1,101,201,2,102,...,即自增值总是在发生跳变。
在 MySQL 数据库中,如果显式地向自增表中插入指定值,则后续生成的自增值都不会小于该值。如果发现插入了一个区间内的值,会放弃自己的缓存。
在 OceanBase 数据库的分布式场景下,当插入一个指定值且该值比自增表中其他值都大(即最大值)时,不仅 OBServer 节点自身需要知道当前插入了一个最大值,还需要同步给其它 OBServer 节点和内部表,该同步动作非常耗时,为了避免每次指定最大值时都执行同步操作,系统会在插入一个最大值时放弃当前的缓存,这样从当前值开始到下一个缓存值前都不需要再进行同步。
例如,当分区表所在的 OBServer1、OBServer2、OBServer3 分别按以下顺序接收到显式指定递增序列(1, 2, 3, ...)的请求时,并且假设这些机器上均保存了缓存:
这样,如果插入部分值后,继续使用自增列来生成序列,就会发生自增值跳变。例如,OBServer1 的第一个区间 [1,100] 都没有使用而是直接跳到了 301。
除了多机环境,单机环境下,插入指定的最大值时,也会出现自增值跳变的问题。示例如下:
创建一个含自增列的表 t1:
obclient> CREATE TABLE t1 (c1 int not null AUTO_INCREMENT) AUTO_INCREMENT_MODE = 'NOORDER';
同时,AUTO_INCREMENT_CACHE_SIZE 的值为 100。
向该表中多次插入数据:
obclient> INSERT INTO t1 VALUES (NULL);
obclient> INSERT INTO t1 VALUES (3);
obclient> INSERT INTO t1 VALUES (NULL);
插入成功后,查看表中的数据:
obclient> SELECT * FROM t1;
查询结果如下:
+-----+
| c1 |
+-----+
| 1 |
| 3 |
| 101 |
+-----+
根据查询结果,发现自增列从 3 跳到了 101。
自增列的缓存是一个内存结构,如果 OBServer 节点的机器发生了重启或宕机,该机器上未使用完的缓存区间不会写回内部表,这就导致未使用的这部分区间不会再被使用。例如,假设 OBServer1 上初始自增列的缓存区间为 [1,100],并且已经生成了自增值 1 和 2。此时,如果 OBServer1 发生了宕机,重启后,该机器上的缓存区间就变成了新的区间 [101,200],同时下一次的自增值为 101,最终自增值的顺序就是 1,2,101,...,即发生了跳变。
为了解决 NOORDER 模式下的自增值跳变问题,OceanBase 数据库在 V4.x 版本中引入了 ORDER 模式。ORDER 模式更好地兼容 MySQL 数据库。它能避免多机多分区生成自增值时的跳变问题。也能避免通过 INSERT 语句插入指定最大值时的跳变问题。
对于 ORDER 模式的自增列,虽然解决了多机多分区生成自增值和通过 INSERT 语句插入指定的最大值等场景下自增值跳变的问题,但是在作为 Leader 的 OBServer 节点的机器重启或宕机、发生切主的场景下,仍然会发生自增值的跳变。
在 ORDER 模式中,作为 Leader 的 OBServer 节点上保存了内存下的缓存区间,当作为 Leader 的 OBServer 节点的机器发生重启或宕机时,该区间内未使用的自增值不会被继续使用,而是使用新的缓存区间,从而导致自增值发生跳变。
该场景下,仅作为 Leader 的 OBServer 节点发生重启或宕机时,才会发生自增值跳变的问题,其他作为 Follower 的 OBServer 节点由于不保存缓存,即使发生了宕机也不会影响自增值生成的连续性。
假设 OBServer2 上的初始自增列的缓存区间为 [1,100],并且已经生成了自增值 1 和 2,当集群内发生切主时,按照常规处理逻辑:
切主到 OBServer1,OBServer1 从内部表申请一段新的自增区间 [101,200],继续生成自增值 101 和 102。 OBServer2 机器重启成功后,再次切回到 OBServer2,继续用上一次的缓存区间 [3,100],生成自增值 3 和 4。 由此可知,从 101 到 3 发生了自增值不递增的问题。
为了避免上述来回切主从而导致的自增值不递增的问题,OceanBase 数据库会在切主时,将原 Leader 的 OBServer 节点上的缓存区间清理掉,从而导致自增值发生了跳变。
| 场景 | NOORDER 模式(最佳性能) | ORDER 模式(最大兼容) |
|---|---|---|
| 多机多分区生成自增列值 | 不同机器分别缓存自增区间,表内整体插入的数据顺序会跳变。但全表自增值不会因跳变而"浪费"。 | 所有的节点都在 leader 申请自增值,所以不会跳变,但性能比 noorder 差。 |
| 显式指定自增列值(INSERT、INSERT ON DUPLICATE UPDATE、REPLACE) | 如果显式向自增列插入指定值,插入后会刷新各节点自增值缓存区间,以保证后续生成的自增值都不会小于该值。存在因缓存刷新导致的自增值跳变和"浪费"。 | 不会跳变。 |
| INSERT ON DUPLICATE UPDATE/REPLACE INTO 场景不指定自增列 | 早期版本需要刷新全局 cache。目前各分支的最新版本都无需再刷新。不会因这个场景特殊跳变。 | 早期版本需要刷新全局 cache。目前各分支的最新版本都无需再刷新。不会因这个场景特殊跳变。 |
| 机器重启/宕机 | 机器重启或宕机后,无法复用宕机前的剩余缓存值区间,需要重新获取。存在因机器重启/宕机导致的自增值跳变和"浪费"。 | 在 leader 节点维护了缓存区间,当 leader 节点发生重启/宕机时,该区间内未使用的自增值不会被继续使用,从而发生跳变和"浪费"。注意,这里跳变的场景仅发生在 leader 节点,其它 follower 节点由于不保存缓存,即使宕机也不会影响自增值生成的连续性。 |
| 主动切主(如升降配、升级 OBServer) | 无切主不跳变的能力 | 老版本发生切主时,会把原始 leader 的缓存区间清理,从而发生跳变和"浪费"。V4.2.3 版本开始,优化为正常切主不跳变,但需要注意:切主会影响服务器的可用性,刚切主完成部分 INSERT 请求可能会存在重试的情况,这样可能会有小范围的数据跳跃。 |
序列的跳变主要来自 CACHE 机制和 ORDER 模式:
CACHE 导致跳变: 当设置 CACHE 100,系统预分配 100 个值。若节点宕机,未使用的值将丢失,重启后从下一个缓存段开始,导致跳变。
NOORDER 模式下并发跳变: 多个会话同时获取 NEXTVAL,不保证顺序,可能乱序返回。
ORDER 模式保证顺序但牺牲性能: 使用 ORDER 可确保序列严格递增,但需加锁协调,影响并发性能。
| 机制 | 建议值 | 说明 |
|---|---|---|
| 自增列缓存 | AUTO_INCREMENT_CACHE_SIZE = 1000000(默认) |
大缓存减少元数据争用,提升性能;但切主时跳变幅度大。可按需调小(如 10000)。支持表级设置。 |
| 序列缓存 | CACHE 100 ~ 1000 |
平衡性能与跳变风险。生产环境避免 NOCACHE(性能差)。 |
| 机制 | 推荐设置 | 说明 |
|---|---|---|
| 自增列 | 默认 ORDER 模式 | 保证全局递增。若允许跳变且追求性能,可设为 NOORDER(仅保证唯一)。 |
| 序列 | NOORDER(默认) | 性能最优。仅在必须严格递增时使用 ORDER。 |
ORDER 模式需跨节点协调,成本高,仅在金融等强有序场景使用。
何时需要将自增列数据类型设置为 BIGINT?
何时允许自增列数据类型保持为 INT?
何时可以将自增列改为 NOORDER?
在单机版本中,ORDER 和 NOORDER 模式的性能差异不明显。然而,在多机(多分区)场景下,NOORDER 模式在高并发情况下的性能优于 ORDER 模式。
何时可以改小自增列 CACHE?
GLOBAL 系统变量
| 参数 | 含义 | 默认值 |
|---|---|---|
AUTO_INCREMENT_CACHE_SIZE |
用于设置缓存的自增值个数 | V4.0 开始默认 100w |
AUTO_INCREMENT_INCREMENT |
用于设置自增步长 | 默认为 1,也支持 session 级设置 |
AUTO_INCREMENT_OFFSET |
用于确定自增列的起始值 | 默认为 1,也支持 session 级设置 |
租户级配置项
| 参数 | 含义 | 默认值 |
|---|---|---|
DEFAULT_AUTO_INCREMENT_MODE |
用于设置默认的自增列自增模式。 • order:自增列数据保持连续且递增 • noorder:自增列只保证自增值唯一 |
V4.0 之前,只支持 noorder; V4.0 及之后版本,新增该配置项,开始支持 order 模式,默认也为 order。 |
表 OPTION
| 参数 | 含义 | 默认值 |
|---|---|---|
AUTO_INCREMENT_MODE |
自增列为 order 还是 noorder 模式 | 未指定时取 DEFAULT_AUTO_INCREMENT_MODE 配置项设置的值。 |
AUTO_INCREMENT_CACHE_SIZE |
控制内存中自增列一次申请缓存的个数 | 未指定时取 AUTO_INCREMENT_CACHE_SIZE 系统变量设置的值。 |
AUTO_INCREMENT_OFFSET |
用于指定表的起始自增值 | 默认值为 1。 |
如果基于性能开销考虑,创建序列时需要如何设置相关属性?
创建序列时,如果设置 ORDER 属性,为了保证全局有序,每一次获取 NEXTVALUE 的操作都需要到中心节点去更新一张特定的内部表,在高并发场景下,可能会存在较高的锁冲突。如果不要求序列值递增,只要求唯一,建议将序列的属性设置为 NOORDER。
同时,对性能要求较高时,还应该关注 CACHE / NOCACHE 这个属性。
在创建序列时,由于默认的 CACHE 值过小,需要手动声明。单机 TPS 为 100 时,CACHE SIZE 建议设置为 360000。
您也可以使用 ORDER + CACHE,每隔 CACHE 个值会操作内部表,可以避免跳变。
当前用户可以通过配置 AUTO_INCREMENT_CACHE_SIZE 来控制内存中自增列一次申请缓存的个数。CACHE SIZE 通常设置越大,性能会越好,但是如果跳变次数多,很可能快速导致自增列耗尽,从而开始报错主键冲突。