转自 http://web4.blog.163.com/blog/static/189694131201132184850561/

今天碰到一个问题,数据库表有一个字段的值是通过sequence来生成的,但是,获取到的数值却并不连续,而且是非常有规律的一下子就跳跃到21,刚开始是怀疑代码的问题,但是代码当中根本就没有操作这个sequence,写代码的人甚至连这个sequence的名字都不知道。然后,就发现, sequence有一个属性是cache size,它的值是20,莫非跟这个有关系?果然如此!
参考:http://blogold.chinaunix.net/u/30637/showart_1277599.html
SEQUENCE — cache 的用处  
在创建序列的语法中,有一个子句为 cache,它的用处是缓存指定个数的序列值。比如你设置的 cache 是20,那么在获取 nextval 时,Oracle 会直接从 cache 中取下一个序列值,如果 cache 中缓存的序列值没有了(比如 cache 中的序列值用完了,或者被手工清空了),那么 Oracle 会再次产生20个序列值,并放置 cache 中供使用,这样有助于提高序列值的获取速度。

下面我们做个测试:
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE    10.2.0.1.0      Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production
SQL> create sequence SEQ_TEST1
  2  minvalue 1
  3  maxvalue 1000
  4  start with 1
  5  increment by 1
  6  cache 20
  7  order;
序列已创建。
-- 刚刚创建的序列必须先用 nextval 来获取一个初始值
SQL> select SEQ_TEST1.currval from dual;
select SEQ_TEST1.currval from dual
       *
ERROR 位于第 1 行:
ORA-08002: 序列 SEQ_TEST1.CURRVAL 尚未在此会话中定义
SQL> select SEQ_TEST1.nextval from dual;
   NEXTVAL
----------
         1
SQL> select SEQ_TEST1.currval from dual;
   CURRVAL
----------
         1
-- 清空 cache 中缓存的序列值
SQL> alter system flush shared_pool;
系统已更改。
-- 查询当前值,没有变化,仍是1
SQL> select SEQ_TEST1.currval from dual;
   CURRVAL
----------
         1
-- 查询下一个值:Oracle 发现 cache 中的序列值没有了,会再次产生20个序列值供使用。
-- 所以这里得到的结果不是2,而是21。
SQL> select SEQ_TEST1.nextval from dual;
   NEXTVAL
----------
        21
-- 再试一次
SQL> alter system flush shared_pool;
系统已更改。
SQL> select SEQ_TEST1.currval from dual;
   CURRVAL
----------
        21
SQL> select SEQ_TEST1.nextval from dual;
   NEXTVAL
----------
        41
-- 问题:Oracle 下一次取的20个值是从哪里开始计算的呢,是 currval + 20,
-- 还是每个 cache + 20 呢?我们试验一下。
SQL> select SEQ_TEST1.nextval from dual;
   NEXTVAL
----------
        42
-- 现在序列的当前值是42。如果是用 currval + 20 来计算,那么清空 cache 后,
-- 获得的 nextval 应该是62;如果是 cache + 20,那应该是 61。
-- 看看实验结果吧:
SQL> alter system flush shared_pool;
系统已更改。
SQL> select SEQ_TEST1.currval from dual;
   CURRVAL
----------
        42
SQL> select SEQ_TEST1.nextval from dual;
   NEXTVAL
----------
        61 
结论:cache 可以用来提高序列值的获取速度,但有可能会浪费一些序列号,应该根据实际情况来设置 cache 的大小。 
也就是说,oracle会把sequence缓存到shared pool里面,如果数据库down掉了,下次再启动的时候就会出现gap。
 
但是,我们的数据库并没有down掉啊,一直都在正常运行呢!
参考:http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:369390500346406705
在这里面tom大师说了,sequence的唯一的用处是保证数值的唯一性,既不保证gap free,也不保证order。
 you cannot expect a sequence to return gap free values. a sequence has one purpose: assign unique numbers to stuff. Nothing else. there will be gaps, gaps are normal, expected, good, ok, fine. they will be there, there is no avoiding them. This is not a problem, it is expected, it is not "fixable" - a "rollback" for example will generate a gap if some session selected a sequence. 
Do not assume they are gap free and all is well in the world.

还说,不用担心sequence会用完,
set cache to 10000 - but don't lower it. 
you'll never run out of values. even if you lose 10,000 per second 
  1* select 999999999999999999999999999/10000/60/60/24/365 from dual
ops$tkyte%ORA9IR2> /
999999999999999999999999999/10000/60/60/24/365
----------------------------------------------
                                    3.1710E+15
that is how many years you would have before running out of values
 
什么时候会出现gap呢?
(1)事务回滚会导致gap
(2)数据库down掉会导致gap
(3)just normal aging of things out of the SGA can cause it.内存用完了也会导致gap的出现。原来我们的问题在这里。我们就是在产生下一个序列号之前使用了一个非常消耗内存的工具,导致oracle缓存的sequence被替换出内存。

但是,tom大师同时也说了,千万不要设置nocache,alter sequence XXX nocache;
do not use nocache - that would be like setting "slow=true" in your init.ora parameter file.
http://blog.csdn.net/tianlesoftware/archive/2010/11/08/5995051.aspx
这篇文章有启用和禁用cache在性能方面的数值比较。
 
如果我们想不出现gap该如何做呢?
那肯定就不能使用sequence了。
CACHE or NOCACHE, if your requirement is truly to make sure there are no gaps, then a sequence is the wrong solution. You may get fewer gaps with NOCACHE, so they may be less noticeable, but you have accepted the possibility of gaps for a requirement that 'demands' no gaps. If you want to use a sequence, you must first negotiate that 'gap-free' requirement away, and make sure none of the design depends on the keys being 'gap-free'. If the requirement sticks, then you have to use some other mechanism - maybe a table of available keys, or something else. Also make sure there is no requirement that they are assigned in order, and no design dependency anywhere that they be assigned in order. Use a timestamp to keep track of 'in what order were these done'; if that's not enough, then you need more thought and more work.
有人说:每次从表里面查询出最大的,然后加1,作为下一条记录的id,但是,如果最大的记录被删掉以后,下一次再插入的记录的id和被删掉的id是一样的,这样的数据会引发混乱。
还有人说,另外定义一个专门存放最大id的表,就两列,表名和当前最大的id,然后需要往表里面插入的时候,select for update,得到下一个id,这就保证id一直往上增加。
这两种方式都得注意,必须要序列化操作,防止多线程导致id重复。

oracle的sequence出现gap的问题的更多相关文章

  1. JDBC读取新插入Oracle数据库Sequence值的5种方法

    Oracle的sequence实现非常灵活,所以也带来一些易用性问题,如何取到新插入记录生成的sequence值与其它数据库有较大差别,本文详国介绍了5种实现读取新插入记录sequence值的方法. ...

  2. Hibernate用Oracle的sequence生成自增Id

    <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBL ...

  3. Oracle Metric sequence load elapsed time

    Oracle Metric sequence load elapsed time The sequence load elapsed time Oracle metric is the amount ...

  4. oracle中sequence(自增序号)的用法

    转载:https://www.cnblogs.com/liuzy2014/p/5794928.html 在oracle中sequence就是序号,每次取的时候它会自动增加.sequence与表没有关系 ...

  5. oracle创建sequence序列语法

    在oracle中sequence就是序号,每次取的时候它会自动增加.sequence与表没有关系 1.create sequence create sequence SEQ_LOG_ID minval ...

  6. oracle关于sequence的个人理解

    oracle关于sequence的个人理解 1. sequence在多用户使用时的同步问题 个人感觉sequence是以连接(会话)为基础,类似于java中使用mysql的一个connection 网 ...

  7. Oracle序列(Sequence)创建、使用、修改、删除

    Oracle对象课程:序列(Sequence)创建.使用.修改.删除,序列(Sequence)是用来生成连续的整数数据的对象.序列常常用来作为主键中增长列,序列中的可以升序生成,也可以降序生成.创建序 ...

  8. oracle之sequence详解

    Oracle提供了sequence对象,由系统提供自增长的序列号,每次取的时候它会自动增加,通常用于生成数据库数据记录的自增长主键或序号的地方. sequence的创建需要用户具有create seq ...

  9. Oracle中sequence的使用方法

    在Oracle数据库中,sequence等同于序列号,每次取的时候sequence会自动增加,一般会作用于需要按序列号排序的地方. 1.Create Sequence (注释:你需要有CREATE S ...

随机推荐

  1. 最全面的 Android 编码规范指南

    最全面的 Android 编码规范指南 本文word文档下载地址:http://pan.baidu.com/s/1bXT75O 1. 前言 这份文档参考了 Google Java 编程风格规范和 Go ...

  2. go语言的unsafe包(转)

    The unsafe Package in Golang Golang的unsafe包是一个很特殊的包. 为什么这样说呢? 本文将详细解释. 来自go语言官方文档的警告 unsafe包的文档是这么说的 ...

  3. Go 程序执行顺序

    在一个 go 程序中通常包含:包.常量.变量.init().main()等元素,如果同时存在多个包,包之间存在依赖关系,每个包中存在多个 init 函数,每个文件中存在多个 init 函数,那么问题来 ...

  4. 03-python的新式类和经典类区别

    新式类就是  class person(object): 这种形式的, 从py2.2 开始出现的 新式类添加了: __name__ is the attribute's name. __doc__ i ...

  5. RR和RC复合语句加锁

    mysql版本:5.7 RR复合语句: insert/update/delete+select,+号左边是影响数据的排他锁,+号右边是查询(当前读,其实相当于lock in share mode)到数 ...

  6. VUE脚手架,babel转码 常用命令

    vue-cli脚手架,单页面应用初始化时 npm -v 查看npm版本号 npm install vue-cli -g  全局安装vue-cli vue -V查看vue版本号,说明vue-cli已经安 ...

  7. C语言——<算法>_冒泡算法的使用及理解

    对数组内数值进行有规则排序时,就要用冒泡算法,也是比较简单的一个算法 #include <stdio.h> #include <stdlib.h> int main() { i ...

  8. 玩转Git之初识Git

    git是什么 Git是一款免费.开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目 Git 和 svn 有什么区别 它们之间的主要区别是Git是分布式的,而svn是集中式. 当然Git也可 ...

  9. JAVA-7NIO之Socket/ServerSocket Channel

    一.ServerSocketChannel Java NIO中的 ServerSocketChannel 是一个可以监听新进来的TCP连接的通道, 就像标准IO中的ServerSocket一样.Ser ...

  10. [转] 如何选择正确的Hadoop版本

    Gartner:如何选择正确的Hadoop版本 这份报告的全名是<How to Choose the Right Apache Hadoop Distribution>.主要介绍了企业如何 ...