小議物化檢視與基表資料不一致的消除(三)

yangtingkun發表於2009-08-31

這篇文章主要討論如何透過修改物化檢視日誌來同步UPDATE操作。

小議物化檢視與基表資料不一致的消除(一):http://yangtingkun.itpub.net/post/468/326751

小議物化檢視與基表資料不一致的消除(二):http://yangtingkun.itpub.net/post/468/327727

 

 

前面一篇文章描述瞭如何透過手工修改物化檢視日誌的方法來實現INSERTDELETE操作的同步。

也許有人認為有了INSERTDELETE的方法就不需要UPDATE的方法了,因為只需要在物化檢視日誌中插入一個DELETE的日誌,然後在插入一個INSERT對應的日誌資訊,Oracle在重新整理物化檢視的時候,就會將需要UPDATE的記錄先刪除,然後重新插入。

但是,事情並不那麼簡單。物化檢視的重新整理並不僅僅依賴於物化檢視日誌中的內容,事實上,Oracle會根據物化檢視和基表的差異來確定是否執行刪除和插入的操作。

關於上面的描述可以參考:物化檢視重新整理並非完全根據物化檢視日誌記錄:http://yangtingkun.itpub.net/post/468/486248

因此想要透過這種手工新增DELETEINSERT記錄的方式來欺騙Oracle是行不通的。UPDATE操作就只能UPDATE的方式來解決。

雖然無法欺騙Oracle,錄音DELETE + INSERT的方式來繞過UPDATE操作,但是在UPDATE操作需要更新的列上可以欺騙一下Oracle

Oracle處於效能的考慮,當表中不包含LOB列時,雖然物化檢視日誌明確的記錄了哪些列需要被更新,但是Oracle並不會將更新細化到列級,而是表中所有的欄位全部更新。這樣的話,在處理UPDATE語句的時候就有了省事的辦法。在物化檢視日誌表中手工編輯UPDATE記錄的時候,可以在列標識的地方輸入任意列,比如’02’。這樣就可以實現物化檢視和基表之前,同一條記錄欄位資料不同的同步操作。

SQL> exec dbms_mview.refresh('MV_T')

PL/SQL procedure successfully completed.

SQL> select * from t;

        ID NAME                                  AGE
---------- ------------------------------ ----------
         1 update                                 18
         2 b                                      26
         3 c                                      34
         4 d                                      40

SQL> select * from mv_t;

        ID NAME                                  AGE
---------- ------------------------------ ----------
         1 a                                      18
         2 b                                      26
         3 c                                      34
         4 d                                      40

現在基表和物化檢視中ID1的記錄是不同的。現在透過手工新增物化檢視日誌的方式來實現二者的同步:

SQL> desc mlog$_t               
 Name                                Null?    Type
 ----------------------------------- -------- ---------------
 ID                                           NUMBER
 SNAPTIME$$                                   DATE
 DMLTYPE$$                                    VARCHAR2(1)
 OLD_NEW$$                                    VARCHAR2(1)
 CHANGE_VECTOR$$                              RAW(255)

SQL> insert into mlog$_t values (1, to_date('4000-1-1', 'yyyy-mm-dd'), 'U', 'U', '01');

1 row created.

SQL> col change_vector$$ format a10
SQL> select * from mlog$_t;

        ID SNAPTIME$$     D O CHANGE_VEC
---------- -------------- - - ----------
         1 01-1
-00     U U 01

SQL> delete t where id = 4;

1 row deleted.

SQL> exec dbms_mview.refresh('MV_T')

PL/SQL procedure successfully completed.

SQL> select * from t;

        ID NAME                                  AGE
---------- ------------------------------ ----------
         1 update                                 18
         2 b                                      26
         3 c                                      34

SQL> select * from mv_t;

        ID NAME                                  AGE
---------- ------------------------------ ----------
         1 update                                 18
         2 b                                      26
         3 c                                      34

第一個欄位表示發生變化的記錄的ID

第二個是時間戳填入400011日,表示任何物化檢視還沒有對這個記錄進行重新整理。

第三個欄位表示INSERT/UPDATE/DELETE

第四個欄位表示新值(N/舊值(O/修改(U)。

最後一個欄位表示修改列的向量。由於UPDATE的時候會更新所有的非LOB列,因此這裡並不需要對應到列上,比如這裡插入的’01’實際上指向的是主鍵列。

關於物化檢視日誌欄位的詳細描述可以參考:http://yangtingkun.itpub.net/post/468/20498

關於物化檢視是如何利用物化檢視日誌進行快速重新整理的可以參考:http://yangtingkun.itpub.net/post/468/20584

修改MLOG後馬上重新整理並不會導致資料同步到物化檢視,這是由於Oracle在快速重新整理的時候發現基表自上次重新整理完成後並未發生修改,因此根本沒有去讀取物化檢視日誌。

因此在上面的例子中對基表資料進行修改,使得物化檢視重新整理時,會讀取手工新增的物化檢視日誌資訊。

可以看到,透過手工修改物化檢視日誌的方式,使得Oracle的基表和物化檢視日誌實現了同步。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-613657/,如需轉載,請註明出處,否則將追究法律責任。

相關文章