1. 程式人生 > >RAC環境下序列快取導致資料庫序列不同步

RAC環境下序列快取導致資料庫序列不同步

 

一、【問題描述】

最近,客戶提出,KC70的醫療賬戶使用餘額與KC04中的賬戶餘額不一致。

二、【分析過程】

根據資料庫後臺包查得,後臺包是根據KC70中最大的OAE001取每個人當前的餘額,按照正常的思路,序列是遞增的,應該不會有問題。

查詢該人的KC70(如上圖),發現有兩條記錄變更前金額一致。仔細觀察發現2010-11-4 8:35產生的KC70記錄的OAE001居然要比後來2010-11-4 20:25產生的OAE011還要大。導致取變更後金額時都取的OAE001大的那條記錄,導致錯誤。

1、  是否存在呼叫不同的序列?

檢視後臺包過程,發現KC70呼叫的統一的是seq_a_rowid 這個序列。不存在呼叫不用序列的問題。

2、  因為用的是資料庫叢集,會不會同一個序列在不同資料庫例項裡是不一樣的?

通過PL/SQL觀察,發現兩個資料庫例項的seq_a_rowid序列的開始值一樣。

3、  用PL/SQL同時連線兩個例項(1和3),同時執行SELECT seq_a_rowid.nextval FROM dual 發現取得的兩個例項居然不是連續的,而且對比兩個產生的序列值,有時候例項1比例項3產生的序列大,有時候例項3又比例項1大。

三、【解決途徑】

其實問題出在了資料庫是個RAC環境,序列是要被共享的,而且檢視序列的建立語句,序列的cache 是8000,是有快取的。rac兩節點中若序列的cache為20的話,在節點一上cache了1-20個,然後節點二上cache了20-40。當從不同的節點來進行對sequence取值的時候,會造成先取的值不一定是小的,後取的值不一定會大。而且預設序列都是noordered的。因此完全有可能會出現這種情況:

在節點1先執行SELECT seq_a_rowid.nextval FROM dual;的值比節點2後執行SELECT seq_a_rowid.nextval FROM dual;大。

            具體的說解決辦法有2個:

           1、設定cache 的值為空。(通過PLSQL檢視顯示為0);

           2、建立序列的時候,增加order屬性,使用cache+order屬性 ;

            簡便方法:

用PL/SQL DEVELOPER 開啟序列設定該序列快取記憶體大小為0,或者排序(ORDER)選項打上。

      oracle為了管理sequence使用了以下三種鎖:

* row cache lock :呼叫sequence.nextval過程中(nocache)

* SQ鎖 : 呼叫sequence.nextval過程中(cache+noorder)

* SV鎖(dfs lock handel) :RAC上節點之間順序得到保障的的前提下,呼叫sequence.nextval期間擁有。賦予了cache + order屬性的sequence上發生。 (cache+order)

row cache lock的目的是在sequence指定nocache的情況下呼叫sequence.nextval過程中保證序列的順序性;

cache引數告訴oracle預先分配一個sequence numbers的集合,並且保留在記憶體中,以便sequence number能夠被快速的訪問。這個記憶體的大小就是cache所指定的大小,當多個使用者同時訪問一個sequence的時候,是在oracle SGA中讀取sequence當前的合理數值,如果併發訪問太大,cache的大小不夠,那麼就會產生sequence cache相關的等待(enq: SQ - contention),影響系統性能。

在RAC多節點環境下,Sequence的Cache屬性對效能的影響很大。應該儘量賦予cache+noorder屬性,並要給予足夠的cache值。

如果需要保障順序,必須賦予cache+order屬性。但這時為了保障順序,例項之間需要不斷的交換資料。因此效能稍差。

四、【經驗總結】

            雖然設定cache 的值為空也可以解決問題,但會使得程式在叢集環境中的效能得到很大的降低。所以請在一般情況下,請使用增加ORDER的方式。

            在叢集環境下,對序列大小順序有要求的時候,必須對按上述的方式對序列進行控制。