oracle的sequence出现gap的问题
转自 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的问题的更多相关文章
- JDBC读取新插入Oracle数据库Sequence值的5种方法
Oracle的sequence实现非常灵活,所以也带来一些易用性问题,如何取到新插入记录生成的sequence值与其它数据库有较大差别,本文详国介绍了5种实现读取新插入记录sequence值的方法. ...
- Hibernate用Oracle的sequence生成自增Id
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBL ...
- Oracle Metric sequence load elapsed time
Oracle Metric sequence load elapsed time The sequence load elapsed time Oracle metric is the amount ...
- oracle中sequence(自增序号)的用法
转载:https://www.cnblogs.com/liuzy2014/p/5794928.html 在oracle中sequence就是序号,每次取的时候它会自动增加.sequence与表没有关系 ...
- oracle创建sequence序列语法
在oracle中sequence就是序号,每次取的时候它会自动增加.sequence与表没有关系 1.create sequence create sequence SEQ_LOG_ID minval ...
- oracle关于sequence的个人理解
oracle关于sequence的个人理解 1. sequence在多用户使用时的同步问题 个人感觉sequence是以连接(会话)为基础,类似于java中使用mysql的一个connection 网 ...
- Oracle序列(Sequence)创建、使用、修改、删除
Oracle对象课程:序列(Sequence)创建.使用.修改.删除,序列(Sequence)是用来生成连续的整数数据的对象.序列常常用来作为主键中增长列,序列中的可以升序生成,也可以降序生成.创建序 ...
- oracle之sequence详解
Oracle提供了sequence对象,由系统提供自增长的序列号,每次取的时候它会自动增加,通常用于生成数据库数据记录的自增长主键或序号的地方. sequence的创建需要用户具有create seq ...
- Oracle中sequence的使用方法
在Oracle数据库中,sequence等同于序列号,每次取的时候sequence会自动增加,一般会作用于需要按序列号排序的地方. 1.Create Sequence (注释:你需要有CREATE S ...
随机推荐
- (转)pt-online-schema-change在线修改表结构
原文:http://www.ywnds.com/?p=4442 一.背景 MySQL大字段的DDL操作:加减字段.索引.修改字段属性等,在5.1之前都是非常耗时耗力的,特别是会对MySQL服务产生影响 ...
- android开发 gradle 总结
gradle结构: MyApp ├── build.gradle ├── settings.gradle └── app └── build.gradle 1. setting.gradle解析 当你 ...
- Jmeter环境搭建
一.工具描述 Apache JMeter是 100 %的 java 桌面应用程序.它可以被用来测试包括基于静态和动态资源程序的性能,例如静态文件, Java Servlets , Java 对象,数 ...
- 编写Android工程里测试代码的步骤
第一步: 写个类去继承 AndroidTestCase public class TestStudent extends AndroidTestCase 并且编写一个测试的方法, 注意,测试的方法必须 ...
- Flow类
JLS参考:https://docs.oracle.com/javase/specs/jls/se7/html/jls-16.html This pass implements dataflow an ...
- Java中的四种引用
引用定义 实际上,Java中存在四种引用,它们由强到弱依次是:强引用.软引用.弱引用.虚引用.下面我们简单介绍下这四种引用: 强引用(Strong Reference):通常我们通过new来创建一个新 ...
- cpu负载的探讨
原链接:http://blog.chinaunix.net/uid-12693781-id-368837.html 摘要:确定cpu的负载的定义,帮助管理员设置cpu负载阀值,推测可能的导致cpu负载 ...
- vue cli+axios踩坑记录+拦截器使用,代理跨域proxy
1.首先axios不支持vue.use()方式声明使用,看了所有近乎相同的axios文档都没有提到这一点 建议方式 在main.js中如下声明使用 import axios from 'axios'; ...
- nginx学习笔记(7)Nginx如何处理一个请求---转载
如何防止处理未定义主机名的请求基于域名和IP混合的虚拟主机一个简单PHP站点配置 基于名字的虚拟主机 Nginx首先选定由哪一个虚拟主机来处理请求.让我们从一个简单的配置(其中全部3个虚拟主机都在端口 ...
- win8.1弹框
在winform或者wp8中用MessageBox.Show()弹框,但是wp8.1中已经不存在了 private async void btn_Click(object sender, Routed ...