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
来访问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 WITH | Sequence的起始值。 |
MINVALUE | Sequence的最小值。 |
MAXVALUE | Sequence的最大值。 说明 如果有参数NOCYCLE,到达最大值后会报如下错误:
|
INCREMENT BY | Sequence的步长。 |
CACHE/NOCACHE | 缓存的大小,为了性能考虑,可以设置较大的缓存,但如果遇到实例重启,缓存内的值会丢失。 |
CYCLE/NOCYCLE | 表示Sequence如果用完了后,是否允许从MINVALUE重新开始。取值:
|
示例:
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;