AliSQL提供了Sequence Engine,简化获取序列值的复杂度。

Sequence Engine介绍

在持久化数据库系统中,无论是单节点中的业务主键,还是分布式系统中的全局唯一值,亦或是多系统中的幂等控制,单调递增的唯一值是常见的需求。不同的数据库系统有不同的实现方法,例如MySQL提供的AUTO_INCREMENT,Oracle、SQL Server提供的SEQUENCE。

在MySQL数据库中,如果业务希望封装唯一值,例如增加日期、用户等信息,使用AUTO_INCREMENT的方法会带来很大不便,在实际的系统设计中,也存在不同的折中方法:

  • 序列值由Application或者Proxy来生成,不过弊端很明显,状态带到应用端会增加扩容和缩容的复杂度。
  • 序列值由数据库通过模拟的表来生成,但需要中间件来封装和简化获取唯一值的逻辑。

AliSQL提供了Sequence Engine,通过引擎的设计方法,尽可能地兼容其他数据库的使用方法,简化获取序列值复杂度。

Sequence Engine实现了MySQL存储引擎的设计接口,但底层的数据仍然使用现有的存储引擎,例如InnoDB或者MyISAM来保存持久化数据,兼容现有的第三方工具(例如Xtrabackup),所以Sequence Engine仅仅是一个逻辑引擎。

Sequence Engine通过Sequence Handler接口访问Sequence对象,实现NEXTVAL的滚动、缓存的管理等,最后透传给底层的基表数据引擎,实现最终的数据访问。

前提条件

实例版本如下:

  • RDS MySQL 8.0(内核小版本为20190816及以上)
  • RDS MySQL 5.7(内核小版本为20210430及以上)
  • RDS MySQL 5.6(内核小版本为20170901及以上)
说明 实例系列不能是三节点企业版。

使用限制

  • Sequence不支持子查询和join查询。
  • 可以使用SHOW CREATE TABLE或者SHOW CREATE SEQUENCE来访问Sequence结构,但不能使用SHOW CREATE SEQUENCE访问普通表。
  • 不支持建表的时候指定Sequence引擎,Sequence表只能通过创建Sequence的语法来创建。

创建Sequence

创建Sequence语句如下:
CREATE SEQUENCE [IF NOT EXISTS] <数据库名>.<Sequence名称>
   [START WITH <constant>]
   [MINVALUE <constant>]
   [MAXVALUE <constant>]
   [INCREMENT BY <constant>]
   [CACHE <constant> | NOCACHE]
   [CYCLE | NOCYCLE]
  ;
说明 方括号([])中的内容非必填。

参数说明如下。

参数 说明
START Sequence的起始值。
MINVALUE Sequence的最小值。
MAXVALUE Sequence的最大值。
说明 如果有参数NOCYCLE,到达最大值后会报如下错误:
ERROR HY000: Sequence 'db.seq' has been run out.
INCREMENT BY Sequence的步长。
CACHE/NOCACHE 缓存的大小,为了性能考虑,可以设置较大的缓存,但如果遇到实例重启,缓存内的值会丢失。
CYCLE/NOCYCLE 表示Sequence如果用完了后,是否允许从MINVALUE重新开始。取值:
  • CYCLE:允许;
  • NOCYCLE:不允许。

示例:

create sequence s
       start with 1
       minvalue 1
       maxvalue 9999999
       increment by 1
       cache 20
       cycle;

为了兼容MySQL Dump的备份方式,您也可以使用另外一种创建Sequence的方法,即创建Sequence表并插入一行初始记录。示例如下:

CREATE TABLE schema.sequence_name (  `currval` bigint(21) NOT NULL COMMENT 'current value',
  `nextval` bigint(21) NOT NULL COMMENT 'next value',
  `minvalue` bigint(21) NOT NULL COMMENT 'min value',
  `maxvalue` bigint(21) NOT NULL COMMENT 'max value',
  `start` bigint(21) NOT NULL COMMENT 'start value',
  `increment` bigint(21) NOT NULL COMMENT 'increment value',
  `cache` bigint(21) NOT NULL COMMENT 'cache size',
  `cycle` bigint(21) NOT NULL COMMENT 'cycle state',
  `round` bigint(21) NOT NULL COMMENT 'already how many round'
) ENGINE=Sequence DEFAULT CHARSET=latin1;

INSERT INTO schema.sequence_name VALUES(0,0,1,9223372036854775807,1,1,10000,1,0);
COMMIT;

Sequence表介绍

由于Sequence是通过真正的引擎表来保存的,所以通过查询创建语句看到仍然是默认的引擎表。示例如下:

SHOW CREATE TABLE schema.sequence_name;

CREATE TABLE schema.sequence_name (
  `currval` bigint(21) NOT NULL COMMENT 'current value',
  `nextval` bigint(21) NOT NULL COMMENT 'next value',
  `minvalue` bigint(21) NOT NULL COMMENT 'min value',
  `maxvalue` bigint(21) NOT NULL COMMENT 'max value',
  `start` bigint(21) NOT NULL COMMENT 'start value',
  `increment` bigint(21) NOT NULL COMMENT 'increment value',
  `cache` bigint(21) NOT NULL COMMENT 'cache size',
  `cycle` bigint(21) NOT NULL COMMENT 'cycle state',
  `round` bigint(21) NOT NULL COMMENT 'already how many round'
) ENGINE=Sequence DEFAULT CHARSET=latin1

查询语法

Sequence支持的查询语法如下:

  • SELECT nextval(<Sequence名称>),currval(<Sequence名称>) FROM <Sequence名称>;
    说明 适用于MySQL 8.0、MySQL 5.7。
  • SELECT <Sequence名称>.currval, <Sequence名称>.nextval FROM dual;
    说明 适用于MySQL 8.0、MySQL 5.7、MySQL 5.6。

示例:

mysql> SELECT test.currval, test.nextval from dual;
+--------------+--------------+
| test.currval | test.nextval |
+--------------+--------------+
|           24 |           25 |
+--------------+--------------+
1 row in set (0.03 sec)
            
说明 新创建的Sequence需要先调用一次该Sequence的NEXTVAL才能正常进行查询,否则会报Sequence 'xxx' is not yet defined in current session错误。

NEXTVAL调用示例:

SELECT <Sequence名称>.nextval FROM dual;