今天早上收到邮件,说有一个很紧急的问题,是关于sequence的。
错误日志里面还有ORA的错误
-----
... 7 more
Caused
by: java.sql.SQLException: ORA-08004: sequence TRX_1SQ.NEXTVAL exceeds
MAXVALUE and cannot be instantiated
猛一看就是sequence的值越界了。
导致这个问题的原因主要有两个:
1)设置的maxvalue值过小了。
2)sequence的cycle模式没有启用
从库里查看sequence的状态。
SEQUENCE_NAME MIN_VALUE MAX_VALUE INCREMENT_BY C O CACHE_SIZE LAST_NUMBER
------------------------------ ---------- ---------- ------------ - - ---------- -----------
TRX_1SQ 1 999999999 1 N N 100 1000000000
从上面的结果可以看出,sequence的cycle模式没有启用,sequence值越界了。
修复问题可以有两种思路。就是设置maxvalue,或者选择开启cycle模式。
先来看看设置maxvalue,问题就来了,需要设置多大,这个得找开发确认,而开发也不确定最大能设置多大。问题又跑到了dba这边,
关于maxvalue的值,官方文档是这么描述的。最大28位。
有了这个思路,貌似问题简单了很多。从数据库层面来说似乎行得通了,设置一个最大值即可。从业务上是不是支持更大的数值呢,这个看似需要开发来确认,但是和dba也是有一些关联的,我找到sequence相关的表,大概有5张左右的表使用了那个sequence, 查看对应的表列,可以看到有些字段是支持的,有些字段却是NUMBER(9),很明显设置maxvalue会带来更多的问题。
因为相关的几个表都是核心表,如果修改表的精度也是有潜在风险的。
这个时候就需要找开发确认,是不是应该开启cycle模式,对于现有数据是否有影响了。很快得到产品线的回馈,有同样一个问题在别的项目发生过,需要开启cycle模式。
对于dba来说,需要做的工作基本就是测试和验证了。
从生产备份库中使用dbms_metadata.get_ddl得到sequence的创建语句
SQL> CREATE SEQUENCE "TRX_1SQ"
MINVALUE 1 MAXVALUE 999999999 INCREMENT BY 1 START WITH 1000000000 CACHE 100
NOORDER NOCYCLE
/
Sequence created.
--复现问题
SQL> select trx_1sq.nextval from dual;
select csm_trx_1sq.nextval from dual
*
ERROR at line 1:
ORA-08004: sequence CSM_TRX_1SQ.NEXTVAL exceeds MAXVALUE and
cannot be
instantiated
--修复问题
SQL> alter
sequence CSM_TRX_1SQ cycle;
Sequence altered.
--验证问题
SQL> select csm_trx_1sq.nextval from dual;
NEXTVAL
----------
1
SQL> /
2
SEQUENCE_NAME
MIN_VALUE MAX_VALUE INCREMENT_BY C O CACHE_SIZE LAST_NUMBER
------------------------------ ---------- ----------
------------ - - ---------- -----------
TRX_1SQ
1 999999999
1 Y N
100 101
当然了,如果要设置maxvalue的话。有一个细节需要注意的。
如果设置为28位,最高位是没有问题的。
SQL> alter sequence csm_trx_1sq maxvalue 9999999999999999999999999999;
SQL> select *from user_sequences where sequence_name='TRX_1SQ';
TRX_1SQ 1 1.0000E+28 1 Y N 100 3
但是如果你设置了30位,也是不会报错的,提示运行成功。但是查看sequence的最大长度,却还是28位。
SQL> alter sequence csm_trx_1sq maxvalue 999999999999999999999999999999;
SQL> select *from user_sequences where sequence_name='CSM_TRX_1SQ';