暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle sequence跳号知多少

1437

Sequence是oracle中的一个非常常用的功能,开发经常会频繁使用。但是在生产环境中经常有应用反馈通过sequence生成的自增主键会出现不连续跳号的现象,而且是几十个几十个地跳,为了弄清楚sequence跳号的原因和机制,进行了一些研究和实验。

 

事务回滚引起的跳号

 

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

SQL> create sequence test_seq

start with 1

increment by 1

Maxvalue 9999999999

Cache 30

Order;

 

Sequence created.

SYS@orcl>select test_seq.nextval from dual;

 

   NEXTVAL

----------

         1

SYS@orcl>insert into test_tab select test_seq.nextval from dual;

 

1 row created.

 

SYS@orcl>rollback;

 

Rollback complete.

 

SYS@orcl>select test_seq.nextval from dual;

 

   NEXTVAL

----------

       3

 

并发访问序列引起的跳号

 

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

Session 1:

 

SYS@orcl>begin

  for i in 1..50000 loop

  Insert into ta select test_seq.nextval from dual;

  end loop;

  end;

  /

PL/SQL procedure successfully completed.

 

Session 2:

 

SYS@orcl>begin

  for i in 1..50000 loop

  insert into tb select test_seq.nextval from dual;

  end loop;

  end;

  /

PL/SQL procedure successfully completed.

 

SYS@orcl>select * from ta where rownum<10;

 

        ID

----------

    466322

    466324

    466326

    466327

    466329

    466330

    466332

    466333

    466335

 

9 rows selected.

 

发现序号并不连续,高并发情况下存在sequence争用。

  

FLUSH SHARED_POOL会导致CACHE的序列跳号

  

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

 

SYS@orcl>alter sequence test_seq cache 30;

 

Sequence altered.

 

SYS@orcl>select test_seq.nextval from dual;

 

   NEXTVAL

----------

    560432

 

SYS@orcl>alter system flush shared_pool;

 

System altered.

 

SYS@orcl>select test_seq.nextval from dual;

 

   NEXTVAL

----------

    560462

 

 

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

  

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

 

SYS@orcl>select test_seq.nextval from dual;

 

   NEXTVAL

----------

560464

 

SYS@orcl>select object_id from dba_objects where object_name='TEST_SEQ';

 

 OBJECT_ID

----------

     20306

 

SYS@orcl>select increment$,minvalue,maxvalue,highwater,cache from seq$ where obj#=20306;

 

INCREMENT$   MINVALUE   MAXVALUE  HIGHWATER      CACHE

---------- ---------- ---------- ---------- ----------

          1           1   9999999999     560492         30

 

SYS@orcl>shutdown abort;

ORACLE instance shut down.

SYS@orcl>startup;

 

SYS@orcl>select test_seq.nextval from dual;

 

   NEXTVAL

----------

560492

而在正常关闭数据库的情况下,sequence没有发生跳号

SYS@orcl>select test_seq.nextval from dual;

 

   NEXTVAL

----------

    560526

 

SYS@orcl>shutdown immediate;

Database closed.

Database dismounted.

ORACLE instance shut down.

SYS@orcl>startup;

ORACLE instance started.

 

Total System Global Area 4375998464 bytes

Fixed Size                  2260328 bytes

Variable Size            1946157720 bytes

Database Buffers         2415919104 bytes

Redo Buffers               11661312 bytes

Database mounted.

Database opened.

SYS@orcl>select test_seq.nextval from dual;

 

   NEXTVAL

----------

560527

 

设置test_seq为nocache,然后异常宕机

SYS@orcl>alter sequence test_seq nocache;

 

Sequence altered.

 

SYS@orcl>select test_seq.nextval from dual;

 

   NEXTVAL

----------

    560528

 

SYS@orcl>shutdown abort;

ORACLE instance shut down.

SYS@orcl>startup;

ORACLE instance started.

 

Total System Global Area 4375998464 bytes

Fixed Size                  2260328 bytes

Variable Size            1946157720 bytes

Database Buffers         2415919104 bytes

Redo Buffers               11661312 bytes

Database mounted.

Database opened.

SYS@orcl>select test_seq.nextval from dual;

 

   NEXTVAL

----------

    560529

 

查阅资料发现数据库正常关闭的情况下,会触发一个update seq$的操作,把当前的sequence.nextval的值更新到seq$.highwater中,从而使得sequence在有cache的情况下,数据库正常关闭未出现nextval跳跃(currval也同样不跳跃);而在数据库异常关闭之时,数据库不能及时将sequence.nextval更新到eq$.highwater从而引起sequence cache中的值丢失,从而可能出现了sequence使用cache导致跳跃的情况

 

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

 

SYS@orcl>select test_seq.nextval from dual;

 

   NEXTVAL

----------

    560530

 

SYS@orcl>exec dbms_shared_pool.keep('test_seq','q');

 

PL/SQL procedure successfully completed.

 

SYS@orcl>alter system flush shared_pool;

 

System altered.

 

SYS@orcl>select test_seq.nextval from dual;

 

   NEXTVAL

----------

560531

 

SYS@orcl>alter sequence test_seq cache 30;

 

Sequence altered.

 

SYS@orcl>select test_seq.nextval from dual;

 

   NEXTVAL

----------

    560532

 

SYS@orcl>shutdown abort

ORACLE instance shut down.

SYS@orcl>startup;

ORACLE instance started.

 

Total System Global Area 4375998464 bytes

Fixed Size                  2260328 bytes

Variable Size            1946157720 bytes

Database Buffers         2415919104 bytes

Redo Buffers               11661312 bytes

Database mounted.

Database opened.

SYS@orcl>select test_seq.nextval from dual;

 

   NEXTVAL

----------

560562

 

其实如果业务允许,单号出现跳号也无所谓的情形最好,如果碰到业务要求绝对不能出现单号出现跳号的情况,那么就不能使用序列号了

 

RAC环境中的sequence

如果是cache下的order,单实例下没有影响,而rac下多实例缓存相同的sequence,如果order的取大量sequence则会出现短暂的资源竞争(由于资源需要在多实例间传递),性能要比noorder差很多。尤其注意nocache order的sequence,即对于sequence大量争用,还需要在实例间传递竞争资源,严重的甚至导致系统直接hang住,对于rac的环境需要通过cache fusion和序列的机制认真分析来找到性能瓶颈的根本原因。

oracle为了在rac环境下为了sequence的一致性,使用了三种锁:row cache lock、SQ锁、SV锁。
row cache lock的目的是在sequence指定nocache的情况下调用sequence.nextval过程中保证序列的顺序性;
SQ锁是应用于指定了cache+noorder的情况下调用sequence.nextval过程中。 
SV 锁(dfs lock handel) 是调用sequence.nextval期间拥有的锁。前提是创建sequence时指定了cache 和order属性 (cache+order)。order参数的目的是为了在RAC上节点之间生成sequence的顺序得到保障。

创建sequence赋予的cache值较小时,有enq:sq-contention等待增加的趋势。 
cache的缺省值是20.因此创建并发访问多的sequence时,cacheh值应取大一些。否则会发生enq:sq-contention等待事件。

rac上创建sequence时,如果指定了cache大小而赋予noorder属性,则各节点将会把不同范围的sequence值cache到内 存上。若两个节点之间都必须通过依次递增方式使用sequence,必须赋予如下的order属性(一般不需要这样做)”sql> create sequence seq_b cache 100 order”。如果是已赋予了cache+order属性的sequence,oracle使用SV锁进行同步。SV锁争用问题发生时的解决方法与sq锁 的情况相同,就是将cache 值进行适当调整。

RAC多节点环境下,Sequence的Cache属性对性能的影响很大。应该尽量赋予cache+noorder属性,并要给予足够的 cache值。如果需要保障顺序,必须赋予cache+order属性。但这时为了保障顺序,实例之间需要不断的交换数据。因此性能稍差。

 


最后修改时间:2020-05-08 00:14:09
文章转载自数据库架构之美,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论