1. 程式人生 > >Oracle中sequences使用時發生主鍵衝突

Oracle中sequences使用時發生主鍵衝突

一,情況說明

     最近現場生產環境,有十多個涉及序列的表,報主鍵衝突。
     現場人員和公司開發人員,只是修改序列的當前值,修改完,開始好用,後來又報錯。

    開發人員:之前有部分功能用錯序列,後來改正過來。這次確定不是用錯序列,需要我們協助分析。

    現場實施人員: 發生這種錯誤,就修改當前值,從表中取出最大的值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這種不是所有人都有機會接觸到的。

而且現場的實施人員,發現序列出現問題,包括開發人員,會做的,就是從表中取出最大值,然後跟序列當前值比較,然後修改序列當前值。