Oracle中sequences使用时发生主键冲突

来源:互联网 发布:华道数据催收工作好吗 编辑:程序博客网 时间:2024/06/05 16:10

转载自:http://www.itpub.net/thread-2068086-1-1.html

一,情况说明

     最近现场生产环境,有十多个涉及序列的表,报主键冲突。
     现场人员和公司开发人员,只是修改序列的当前值,修改完,开始好用,后来又报错。

    开发人员:之前有部分功能用错序列,后来改正过来。这次确定不是用错序列,需要我们协助分析。

    现场实施人员: 发生这种错误,就修改当前值,从表中取出最大的值B,然后再B基础上加几千或者几万。

这个主键冲突很多情况:比如开发曾经用错了序列;转数据的人员,之前转错了;或者人为修改了数据


二,情况分析
       网上查了很多资料,自己也分析了很久,都无法解释这种现象,也**去国外论坛,看了TOM关于序列的答复,后来发现都解释不了这种情况。无奈,今天上班,远程到生产环境,做测试,进行模拟,结合假设。后来分析出原因。

1.现场序列情况:
    现场seq都是 采取 noorder+cache 5000 模式 ,是2个实例,简称节点1和节点2

2.基础知识:--此处简单说下,具体可以百度,网上很多关于cache,order,noorder,cycle的解释

       2.1 cache是缓存,[size=14.6667px]默认20. 现场是5000,简单说,如果是没有cache,那么读取一个SEQ.NEXTVAL,就要更新一次序列基表sys.seq$. 如果是5000缓存,就一次性读取5000在内存中,然后直到5000个序列用完了,才去更新一次基表sys.seq$. 大大提高了性能,因为之前在高并发会产生大量的等待,锁。

       2.2 order是排序,如果选择order,rac为保持序列有序,会不停的在节点之间通信并维护序列顺序。用tom大师的话,想系统崩溃在rac就用order吧。

3. 在rac中序列的情况是下面2种情况。


3.1 不修改序列当前值,正常情况

假设序列的cache =10 ,假设2个节点。分别为node1和node2,那么是如下情况
node1=1-10
node2=11-20


然后,假设node1的预先缓存的10个序列先用完,node1会更新基表,并获取cache数量的新序列数。则此时内存中序列是下面
node1=21-30
node2=11-20

结论:也就是说,正常rac节点的序列是,当一个节点的缓存序列使用完毕,另外一个节点的序列是保留的,不刷新。只是使用完毕的节点去更新sys.seq$并重新获得
cache数量的序列。


3.2  修改序列当前值的情况(最后面有真实的图)
假设序列的cache =10 ,假设2个节点。分别为node1和node2,那么初始如下情况
node1=1-10
node2=11-20

此时,由于某些原因,比如node1节点的会话已经使用了上面1-10里面的1,2,3,4 。然后修改序列当前值=8

node1=8-18
node2=19-29


结论:rac,任何节点修改了序列的当前值,之前分配给各个节点的序列号段,都会作废,重新根据当前值在2个节点 生成新的序列。



================================================================================


 


不是我泼冷水,你写的东西真的。。。。 不清不楚~

1. 首先 sequence 的nextvalue是多少和使用它的会话提交还是不提交没人任何关系~
2. 你所谓的“修改序列的当前值”的操作,压根就不存在,或者说根本就不是正确操作~
3. 你根本没有描述出你这个现象出现的的根本原因~


你一直在提到“修改序列的当前值”,其实除了标准的使用select seq.nextvalue from dual以外,没有什么正确的方法“修改序列当前值”,而且从seq的设计角度出发,根本就不应该去做所谓的“修改序列的当前值”操作~

你这个现象应该是有人对一个cache的sequences,使用第三方工具进行了修改,而这种修改本身就是不应该做的。

经常碰到这样的事儿,使用sequence的人,根本不理解sequence的设计初衷,错误的将这个东西当作一个数组来使用~

还没事儿修改last_number, 而且还用第三方工具去修改,因为第三方工具都是展示你点击sequnce图标时状态,使用者在图形界面上修改,也不想想对应的SQL是什么,就点击确定,在他点击确定之前,这个sequence的last_number早就不是它所看到的last_number; 而他点击确定修改时,后台执行的SQL还是用展现时的last_number来作为起点;对于一个cache的sequnce来说,图形展示的last_number还不是nextvlaue,就更乱了~
出现duplicate value完全是错误操作造成的,而这个错误操作就是没事儿修改sequence的last_number(还在sequece正在被使用的时候修改);

正确使用sequence,压根就不可能有要修改last_number的需求

首先前面已经说了,正确使用sequence(正确理解sequence用途)的人,绝对不会提出修改sequence当前值的需求~
其次,你提到的“从表中取出最大的值B”本身也是错误的

要知道,很多开发人员,和实施人员,是不会去了解SEQUENCE的,只是简单的知道这个东西会自动增加1。包括今天研究之前,我也是这么理解的。特别是RAC更不是谁都了解,因为RAC这种不是所有人都有机会接触到的。

而且现场的实施人员,发现序列出现问题,包括开发人员,会做的,就是从表中取出最大值,然后跟序列当前值比较,然后修改序列当前值。