ORACLE SEQUENCE跳号总结

 

    在ORACLE数据库中,序列(SEQUENCE)是使用非常频繁的一个数据库对象,但是有时候会遇到序列(SEQUECNE)跳号(skip sequence numbers)的情形,那么在哪些情形下会遇到跳号呢?

 

 

事务回滚引起的跳号

 

 

不管序列有没有CACHE、事务回滚这种情况下,都会引起序列的跳号。如下实验所示:

 

SQL> create sequence my_sequence
  2  start with 1
  3  increment by 1
  4  maxvalue 99999
  5  nocache;
 
Sequence created.
 
SQL>  create table test(id number(10), name varchar2(32));
 
Table created.
 
SQL> insert into test
  2  select my_sequence.nextval , 'kerry' from dual;
 
1 row created.
 
SQL> 
SQL> rollback;
 
Rollback complete.
 
SQL> select my_sequence.nextval from dual;
 
   NEXTVAL
----------
         3
 
SQL> 

 

 

并发访问序列引起的跳号

 

 

并发访问序列引起的跳号,其实不算真正的跳号,而只是逻辑跳号,只是序列值被其它并发会话使用了。我们来构造一起并发访问序列引起的跳号,我们开启两个会话窗口,循环获取序列的值,模拟并发出现的场景。

 

会话窗口A:

 

exec dbms_lock.sleep(2); --延迟2秒执行,根据你实验情况调整
/
begin
    for i in 1 .. 2000 loop
        dbms_output.put_line(my_sequence.nextval);
    end loop;
end;
/

 

会话窗口B:

 

spool test.txt;
begin
    waitfor delay '00:00:10';
    for i in 1 .. 2000 loop
        dbms_output.put_line(my_sequence.nextval);
    end loop;
end;
/
spool off; 

 

如下所示,我构造的实验当中,你会看到序列的跳号情况。

 

 

 

 

 

FLUSH SHARED_POOL会导致CACHE的序列跳号

 

 

实验测试如下所示(序列的CACHE值必须大于0),当然正常情况下,很难遇到这种情况。

 

SQL> select test.my_sequence.nextval from dual;
 
   NEXTVAL
----------
     17004
 
SQL> alter sequence test.my_sequence cache 40;
 
Sequence altered.
 
SQL> select test.my_sequence.nextval from dual;
 
   NEXTVAL
----------
     17005
 
SQL> alter system flush share_pool;
alter system flush share_pool
*
ERROR at line 1:
ORA-02000: missing SHARED_POOL/BUFFER_CACHE/GLOBAL CONTEXT keyword
 
 
SQL> alter system flush shared_pool;
 
System altered.
 
SQL> select test.my_sequence.nextval from dual;
 
   NEXTVAL
----------
     17045

 

 

 

 

数据库实例异常关闭导致跳号

 

 

如下实验所示,当数据库使用shutdown abort命令关闭后,重新启动实例,序列缓存在shared pool里面没有用过的值都没有了。一下子从17045跳到17085

 

SQL> select test.my_sequence.currval from dual;
 
   CURRVAL
----------
     17045
 
SQL> select object_id from dba_objects where object_name=upper('my_sequence');
 
 OBJECT_ID
----------
     97760
 
SQL> select increment$, minvalue, maxvalue,highwater, cache
  2  from seq$ where obj#=97760;
 
INCREMENT$   MINVALUE   MAXVALUE  HIGHWATER      CACHE
---------- ---------- ---------- ---------- ----------
         1          1      99999      17085         40
 
SQL> shutdown abort;
ORACLE instance shut down.
SQL> startup;
ORA-32004: obsolete or deprecated parameter(s) specified for RDBMS instance
ORACLE instance started.
 
Total System Global Area 1620115456 bytes
Fixed Size                  2213816 bytes
Variable Size            1258293320 bytes
Database Buffers          352321536 bytes
Redo Buffers                7286784 bytes
Database mounted.
Database opened.
SQL> select test.my_sequence.currval from dual;
select test.my_sequence.currval from dual
            *
ERROR at line 1:
ORA-08002: sequence MY_SEQUENCE.CURRVAL is not yet defined in this session
 
SQL> select test.my_sequence.nextval from dual;
 
   NEXTVAL
----------
     17085
 
SQL> 

 

 

另外,我们也来看看正常关闭数据库的情况下,序列会不会出现跳号,我们采用10046跟踪事件,看看正常数据库关闭情况下,会对序列做一些啥操作

 

 

SQL> select test.my_sequence.nextval from dual;
 
   NEXTVAL
----------
     17085
 
SQL> alter session set events '10046 trace name context forever, level 4';
 
Session altered.
 
SQL> shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup
ORA-32004: obsolete or deprecated parameter(s) specified for RDBMS instance
ORACLE instance started.
 
Total System Global Area 1620115456 bytes
Fixed Size                  2213816 bytes
Variable Size            1258293320 bytes
Database Buffers          352321536 bytes
Redo Buffers                7286784 bytes
Database mounted.
Database opened.
SQL> select test.my_sequence.currval from dual;
select test.my_sequence.currval from dual
            *
ERROR at line 1:
ORA-08002: sequence MY_SEQUENCE.CURRVAL is not yet defined in this session
 
 
SQL> select test.my_sequence.nextval from dual;
 
   NEXTVAL
----------
     17086
 
SQL> 

 

 

Trace文件中有更新seq$数据字典表,如果你看过我这篇文章ORACLE中seq$表更新频繁的分析,基本上就知道其实seq$中维护的是序列的一些信息。通过跟踪文件,我们知道在数据库正常关闭的情况下,会触发一个update seq$的操作,把当前的sequence.nextval的值更新到seq$.highwater中,从而使得sequence在有cache的情况下,数据库正常关闭未出现nextval跳跃(currval也同样不跳跃);而在数据库异常关闭之时,数据库不能及时将sequence.nextval更新到eq$.highwater从而引起sequence cache中的值丢失,从而可能出现了sequence使用cache导致跳跃的情况

 

 

=====================
PARSING IN CURSOR #25 len=129 dep=1 uid=0 oct=6 lid=0 tim=1504236336294194 hv=2635489469 ad='bf780410' sqlid='4m7m0t6fjcs5x'
update seq$ set increment$=:2,minvalue=:3,maxvalue=:4,cycle#=:5,order$=:6,cache=:7,highwater=:8,audit$=:9,flags=:10 where obj#=:1
END OF STMT
PARSE #25:c=0,e=21,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,plh=1935744642,tim=1504236336294194
BINDS #25:
 Bind#0
  oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
  oacflg=18 fl2=0001 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=bf45ca48  bln=24  avl=02  flg=09
  value=1
 Bind#1
  oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
  oacflg=18 fl2=0001 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=bf45ca5a  bln=24  avl=02  flg=09
:/17086                                                                                                                                                                     
 Bind#3
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=08 fl2=0001 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=2b7d80f57350  bln=24  avl=01  flg=05
  value=0
 Bind#4
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=08 fl2=0001 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=2b7d80f57320  bln=24  avl=01  flg=05
  value=0
 Bind#5
  oacdty=02 mxl=22(02) mxlc=00 mal=00 scl=00 pre=00
  oacflg=18 fl2=0001 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=bf47b85e  bln=24  avl=02  flg=09
  value=40
 Bind#6
  oacdty=02 mxl=22(04) mxlc=00 mal=00 scl=00 pre=00
  oacflg=18 fl2=0001 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=bf47b870  bln=24  avl=04  flg=09
  value=17086
 Bind#7
  oacdty=01 mxl=32(32) mxlc=00 mal=00 scl=00 pre=00
  oacflg=18 fl2=0001 frm=01 csi=873 siz=32 off=0
  kxsbbbfp=bf47b882  bln=32  avl=32  flg=09
  value="--------------------------------"
 Bind#8
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=08 fl2=0001 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=2b7d80f572f0  bln=24  avl=02  flg=05
  value=8
 Bind#9
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=08 fl2=0001 frm=00 csi=00 siz=24 off=0
  kxsbbbfp=2b7d80f57380  bln=22  avl=04  flg=05
  value=97760
EXEC #9:c=999,e=709,p=0,cr=1,cu=2,mis=0,r=1,dep=1,og=4,plh=1935744642,tim=1504236336297033
CLOSE #9:c=0,e=2,dep=1,type=3,tim=1504236336297058

 

mealink上提到了使用dbms_shared_pool.keep将对象在锁定在shared pool 中,永远不释放。这样可以防止FLUSH SHARED POOL导致序列跳号,但是这个无法避免数据库异常关闭或CRASH引起的跳号

 

SQL> select test.my_sequence.currval from dual;
 
   CURRVAL
----------
     17086
 
SQL> exec dbms_shared_pool.keep('test.my_sequence','q');
 
PL/SQL procedure successfully completed.
 
SQL> alter system flush shared_pool;
 
System altered.
 
SQL> select test.my_sequence.currval from dual;
 
   CURRVAL
----------
     17086
SQL> shutdown abort
ORACLE instance shut down.
SQL> startup
ORA-32004: obsolete or deprecated parameter(s) specified for RDBMS instance
ORACLE instance started.
 
Total System Global Area 1620115456 bytes
Fixed Size                  2213816 bytes
Variable Size            1258293320 bytes
Database Buffers          352321536 bytes
Redo Buffers                7286784 bytes
Database mounted.
Database opened.
SQL> select test.my_sequence.nextval from dual;
   NEXTVAL
----------
     17126

 

 

 

其实如果业务允许,单号出现跳号也无所谓的情形最好,如果碰到业务要求绝对不能出现单号出现跳号的情况,那么就不能使用序列号了,就必须使用其它替代方案,此处不做展开说明!

 

 

 

参考资料:



Sequence Number Generator Generating Numbers With Gaps (文档 ID 470784.1)

Using the Oracle DBMS_SHARED_POOL Package (文档 ID 61760.1)

http://www.xifenfei.com/2015/04/%E6%AD%A3%E5%B8%B8%E5%85%B3%E9%97%AD%E6%95%B0%E6%8D%AE%E5%BA%93sequence-cache%E4%B8%8D%E4%B8%BA0-sequence%E4%B8%8D%E8%B7%B3%E8%B7%83.html

 

时间: 2024-09-15 23:22:44

ORACLE SEQUENCE跳号总结的相关文章

oracle中通过update _NEXT_OBJECT 实现obj$.obj#和obj$.dataobj#跳号

在一些特殊的情况下(比如ORA-00600 [15267],ORA-00600 [KKDLCOB-OBJN-EXISTS],Ora-600 [15260]),考虑需要把dba_objects中的object_id往前推进,这里通过试验的方法实现该功能 数据库版本信息 SQL> select * from v$version;   BANNER ---------------------------------------------------------------- Oracle Datab

ORACLE SEQUENCE的用法

在oracle中sequence就是所谓的序列号,每次取的时候它会自动增加,一般用在需要按序列号排序的地方. 1.Create Sequence 你首先要有CREATE SEQUENCE或者CREATE ANY SEQUENCE权限, CREATE SEQUENCE emp_sequence INCREMENT BY 1  -- 每次加几个 START WITH 1    -- 从1开始计数 NOMAXVALUE      -- 不设置最大值 NOCYCLE         -- 一直累加,不循

Oracle sequence序列的入门级教程

sequence含义  Oracle数据库提供了sequence对象,由系统提供自增长的序列号,通常用于数据库数据记录的自增长主键或序号的地方:南京OCM培训  创建语法格式及说明  Create  sequencemysequenc              --自定义序列名称   Increment by 1                                   --设定步长值,即每次增加或减少的等差序列   Start with 1                      

详解ORACLE SEQUENCE用法_oracle

在oracle中sequence就是序号,每次取的时候它会自动增加.sequence与表没有关系. 1.Create Sequence 首先要有CREATE SEQUENCE或者CREATE ANY SEQUENCE权限. 创建语句如下: CREATE SEQUENCE seqTest INCREMENT BY 1 -- 每次加几个 START WITH 1 -- 从1开始计数 NOMAXvalue -- 不设置最大值 NOCYCLE -- 一直累加,不循环 CACHE 10; --设置缓存ca

Oracle创建自增字段--ORACLE SEQUENCE的简单使用介绍_oracle

先假设有这么一个表: 复制代码 代码如下: create table S_Depart ( DepartId INT not null, DepartName NVARCHAR2(40) not null, DepartOrder INT default 0, constraint PK_S_DEPART primary key (DepartId) ); 在oracle中sequence就是所谓的序列号,每次取的时候它会自动增加,一般用在需要按序列号排序的地方. 1.Create Sequen

Hibernate Oracle sequence的使用技巧_oracle

一.为表创建自增长自段有两种,一种是不同的表使用各自的Sequence,方法如下: 1.在Oracle sequence首先创建sequence create sequence seq_idminvalue 1start with 1increment by 1cache 20; 2.在你的hbm.xml中的配置 seq_id 这样再插入数据的时候,Hibernate会自动生成如下语句: hibernate: select seq_id.nextval from dual hibernate:

oracle中scn号是commit之后产生的,还是commit之前产生的?

问题描述 oracle中scn号是commit之后产生的,还是commit之前产生的? 如果是commit之后产生的,那么在commit之前scn都没有,还怎么用比较scn号大小的方法来实现读一致性呢? 假设scn号是在commit之后产生的,在判断读一致性时是根据scn号的大小去控制的,比如事务开始时最大的scn号是1000,当读到此事务开始之后有人修改过但未提交的数据时,比如这次修改的scn是1001,系统一看比事务开始时最大的scn号1000还大,就直接去undo中读取被修改之前的数据来保

oracle sequence语句重置方介绍_oracle

在开发过程中,可能会用到oracle sequence语句,本文以oracle sequence语句如何重置进行介绍,需要的朋友可以参考下Oracle重置sequence语句1 Sql代码 复制代码 代码如下: DECLARE n NUMBER(10 ); tsql VARCHAR2(100 ); p_seqName varchar2(20 ); BEGIN p_seqName := 'SEQ_RUN_ID'; EXECUTE IMMEDIATE 'SELECT ' || p_seqName |

javascript:查找“跳号”号码

业务背景:航空货运系统中,"货运代理商"会定期从"航空公司"领取一定数量的纸质运单(每张纸上有一个单号),这些单号都是连续的(即:每次可以理解为领取一个"号段"),而且每张单子都要向航空公司交纳一定的费用(即:单号是有价的资产). 实际使用中,货运代理商希望下级的各营业点连续把单号用完,如果出现未连续使用的情况(即:所谓的跳号),要求快速找出来,给予提醒,提示用户优先使用跳号的运单.(否则这些运单号,一直可能不被注意到,造成浪费,而且每到期末跟航