物化檢視日誌結構與ORA-12034 Mview log younger than last refresh

tangyunoracle發表於2012-05-10
我們都知道,要建立快速重新整理的物化檢視,必須先在MASTER SITE端建立物化檢視日誌。這裡介紹一下Mview Log 的結構與江門NGBOSS和之前來電三期中出現的ORA-12034 materialized view log younger than last refresh問題的原因。
我們先來看一下物化檢視日誌的結構含義和用途:物化檢視日誌的名稱為MLOG$_後面跟基表的名稱,如果表名的長度超過20位,則只取前20位,當截短後出現名稱重複時,Oracle會自動在物化檢視日誌名稱後面加上數字作為序號。
物化檢視日誌的建立可以指定為PRIMARY KEY、ROWID、和OBJECT ID幾種型別,同時還可以指定SEQUENCE或明確指定列名。每種物化檢視的結構都會有一些差異,不過它們都會包含以下列:
SNAPTIME$$:用於表示重新整理時間。
DMLTYPE$$:用於表示DML操作型別,I表示INSERT,D表示DELETE,U表示UPDATE。
OLD_NEW$$:用於表示這個值是新值還是舊值。(N)表示新值,(O)表示舊值,U表示UPDATE操作。
CHANGE_VECTOR$$表示修改向量,用來表示被修改的是哪個或哪幾個欄位。
物化檢視日誌預設為PRIMARY KEY,這種型別的物化檢視日誌中會包含主鍵列。
如果WITH後面跟了ROWID,則物化檢視日誌中會包含:
M_ROW$$:用來儲存發生變化的記錄的ROWID。
如果WITH後面跟了OBJECT ID,則物化檢視日誌中會包含:
SYS_NC_OID$:用來記錄每個變化物件的OBJECT ID。
如果WITH後面跟了SEQUENCE,則物化檢視日子中會包含:
SEQUENCE$$:給每個操作一個SEQUENCE號,從而保證重新整理時按照順序進行重新整理。
如果WITH後面跟了一個或多個COLUMN名稱,則物化檢視日誌中會包含這些列。
官方解釋:
OBJECT ID:Specify OBJECT ID to indicate that the system-generated or user-defined object identifier of every modified row should be recorded in the materialized view log.
Restriction on OBJECT ID:You can specify OBJECT ID only when creating a log on an object table, and you cannot specify it for storage tables.
PRIMARY KEY:Specify PRIMARY KEY to indicate that the primary key of all rows changed should be recorded in the materialized view log.
ROWID:Specify ROWID to indicate that the rowid of all rows changed should be recorded in the materialized view log.
SEQUENCE:Specify SEQUENCE to indicate that a sequence value providing additional ordering information should be recorded in the materialized view log. Sequence numbers are necessary to support fast refresh after some update scenarios.[@more@]接下來我們看一下物化檢視日誌中的內容:
SQL> create table t_ty(pid number(2),pname varchar2(20),constraint t_ty_pk primary key(pid));
Table created.
SQL> create materialized view log on t_ty;
Materialized view log created.
SQL> desc mlog$_t_ty;
Name Null? Type
----------------------------------------- -------- ----------------------------
PID NUMBER(2)
SNAPTIME$$ DATE
DMLTYPE$$ VARCHAR2(1)
OLD_NEW$$ VARCHAR2(1)
CHANGE_VECTOR$$ RAW(255)
XID$$ NUMBER
這裡預設是with primary key的物化檢視日誌,所以這裡把主鍵欄位pid加到物化檢視日誌中來,其他型別的物化檢視日誌會換成m_row$$、sys_nc_oid$欄位。這裡如果with中加入sequece或者指定一個或者多個欄位,物化檢視日誌中就會包含SEQUENCE$$或者這些指定的列。下面看一下對錶進行增、刪、改後物化檢視日誌的內容:
SQL> insert into t_ty values(1,'ty');
1 row created.
SQL> insert into t_ty values(2,'snc');
1 row created.
SQL> update t_ty set pname='shsnc' where pid=2;
1 row updated.
SQL> update t_ty set pid=3 where pid=1;
1 row updated.
SQL> select pid,snaptime$$ ,dmltype$$,old_new$$,change_vector$$ from mlog$_t_ty;
PID SNAPTIME$$ DMLTYPE$$ OLD_NEW$$ CHANGE_VECTOR$$
----- ------------------------- -------------- ------------------ -----------------------
1 4000-01-01 00:00:00 I N FE
2 4000-01-01 00:00:00 I N FE
2 4000-01-01 00:00:00 U U 04
1 4000-01-01 00:00:00 D O 00
3 4000-01-01 00:00:00 I N FF
可以看到普通欄位的更新會在日誌中記錄一條更新記錄,如果是更新主鍵欄位,則會先刪除後插入一條新的記錄。DMLTYPE$$、OLD_NEW$$這兩個欄位上面已經介紹過了,結合這裡的日誌內容可以一目瞭然。這裡先介紹一下CHANGE_VECTOR$$欄位,SNAPTIME$$欄位在後面結合江門NGBOSS和之前來電三期中出現的ORA-12034 materialized view log younger than last refresh一塊介紹。
CHANGE_VECTOR$$列是RAW型別,用於記錄修改向量,上面有四個值FE、04、00、FF。插入操作:插入操作用FE表示,如果表中列的個數大於8個,則在右邊新增FF即FEFF,大於16個時,則在後面新增FFFF即FEFFFF。其實oracle是bit來計算列是個數,大於8個列時,十六進位制的FF轉換成二進位制11111111已經無法表示全部的列的狀態了。
刪除操作:刪除操作則用00表示,如果列的個數大於8個時則在後面新增00,以此類推。更新操作:更新操作分為主鍵列更新和非主鍵列的更新,如果是更新主鍵列,在日誌中記錄一條刪除和一條插入,這時插入操作的FE換成FF,其他的生成方式沒變。當更新某些列時,如果更新第一個列則02,即00000010,如果列的個數則在後面補充00,如果更新第二個列則為04,即00000100,即第幾個列被更新則對應的二進位制+1位由0變為1;比如第三和第五位更新則為00101000即十六進位制的28。這裡需要注意的是,如果表的列大於8個,則在右邊補充兩位,但在計算時右邊兩位為高位,比如第11和第17列被更新則為00000010 00001000 00000000即十六進位制的000802。
下面結合江門NGBOSS和之前來電三期中出現的ORA-12034 materialized view log younger than last refresh介紹一下SNAPTIME$$欄位,這個欄位其實也是物化檢視重新整理最主要的依據。
先描述一下江門NGBOSS和之前來電三期的場景和出現的問題,來電三期是從管理節點分別向兩個呼叫節點分發資料,物化檢視每10秒中重新整理一次。江門NGBOSS是需要融合計費建一張物化檢視到CRM生產使用者下,後面由於測試需要另外在源表上建一張物化檢視到CRM的效能使用者下,重新整理時間均為1分鐘。從場景和需求來看都是沒有問題的,但是在建立物化檢視時,卻都出現了ORA-12034 materialized view log younger than last refresh。經過分析發現兩次問題出現的場景有一個共同特點,那就是物化檢視日誌都是被重建過。瞭解物化檢視重新整理的原理就可以很清楚的知道問題的原因了,而物化檢視重新整理的機制恰恰是隱藏在物化檢視的SNAPTIME$$欄位中。下面結合例子,其實也就是上面的場景重現來介紹SNAPTIME$$欄位。
建立物化檢視基表並插入資料:
SQL> create table t_mv(pid number(4),pname varchar2(20),pdept varchar2(30), constraint pk_t_mv primary key(pid));
Table created.
SQL> declare
2 begin
3 for i in 1..99 loop
4 insert into t_mv values (i,'snc'||i,'諮詢測試部'||i);
5 commit;
6 end loop;
7 end;
8 /
PL/SQL procedure successfully completed.
SQL> create materialized view log on t_mv;
Materialized view log created.
模擬第一個物化檢視端建立物化檢視,建立一個1小時的物化檢視:
SQL> create materialized view mv_1
2 refresh fast
3 start with sysdate
4 next sysdate + 1/24 /*1h*/
5 with primary key
6 as
7 select * from t_mv;
Materialized view created.
SQL> insert into t_mv values (21,'shsnc','諮詢');
1 row created.
這裡看一下SNAPTIME$$欄位
SQL> select snaptime$$ from mlog$_t_mv;
SNAPTIME$$
-------------------
4000-01-01 00:00:00
建立第二個物化檢視
SQL> create materialized view mv_2
2 refresh fast
3 start with sysdate
4 next sysdate + 1/24 /*10s*/
5 with primary key
6 as
7 select * from t_mv;
Materialized view created.
SNAPTIME$$欄位的值已經修改為第二個物化檢視建立的時間(這裡也可以解釋後面為什麼會出現ORA-12034的錯誤),這是因為第一個物化檢視的最後重新整理時間比第二個物化建立時間早,用於第一個物化檢視重新整理。
SQL> select snaptime$$ from mlog$_t_mv;
SNAPTIME$$
-------------------
2012-05-06 01:23:34
SQL> select distinct owner, name mview, master_owner master_owner, last_refresh from dba_mview_refresh_times;
OWNER MVIEW MASTER_OWNER LAST_REFRESH
---------- -------------- ------------------------ ---------------------
TY MV_1 TY 06-MAY-12 01:19:10
TY MV_2 TY 06-MAY-12 01:23:35
SQL> insert into t_mv values (22,'shsnc','諮詢');
1 row created.
SQL> select snaptime$$ from mlog$_t_mv;
SNAPTIME$$
---------------------
06-MAY-12 01:23:34
01-JAN-00 00:00:00
這裡為了清晰,手動重新整理物化檢視,模擬物化檢視正常重新整理。
SQL> exec dbms_mview.refresh('MV_1','F');
PL/SQL procedure successfully completed.
SQL> select snaptime$$ from mlog$_t_mv;
SNAPTIME$$
---------------------
06-MAY-12 01:33:04
SQL> select distinct owner, name mview, master_owner master_owner, last_refresh from dba_mview_refresh_times;
OWNER MVIEW MASTER_OWNER LAST_REFRESH
---------- -------------- ------------------------ ---------------------
TY MV_1 TY 06-MAY-12 01:33:04
TY MV_2 TY 06-MAY-12 01:23:35
SQL> select snaptime$$ from mlog$_t_mv;
SNAPTIME$$
---------------------
06-MAY-12 01:33:04
SQL> exec dbms_mview.refresh('MV_2','F');
PL/SQL procedure successfully completed.
SQL> select distinct owner, name mview, master_owner master_owner, last_refresh from dba_mview_refresh_times;
OWNER MVIEW MASTER_OWNER LAST_REFRESH
---------- -------------- ------------------------ ---------------------
TY MV_1 TY 06-MAY-12 01:33:04
TY MV_2 TY 06-MAY-12 01:38:47
SQL> select snaptime$$ from mlog$_t_mv;
no row selected
這裡可以很清楚的看到多個物化檢視都是根據同一個物化檢視日誌來進行重新整理的,根據對物化檢視日誌和物化檢視的最後重新整理時間來對物化檢視重新整理進行管理,當基於基表的所有物化檢視都重新整理後,物化檢視日誌就會被清除。
SQL> drop materialized view log on t_mv;
Materialized view log dropped.
SQL> exec dbms_mview.refresh('MV_1','F');
BEGIN dbms_mview.refresh('MV_1','F'); END;
*
ERROR at line 1:
ORA-23413: table "TY"."T_MV" does not have a materialized view log
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2563
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2776
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2745
ORA-06512: at line 1
SQL> select distinct owner, name mview, master_owner master_owner, last_refresh from dba_mview_refresh_times;
OWNER MVIEW MASTER_OWNER LAST_REFRESH
---------- -------------- ------------------------ ---------------------
TY MV_1 TY 06-MAY-12 01:48:41
TY MV_2 TY 06-MAY-12 01:38:47
當物化檢視日誌被刪除,此時在重新整理物化檢視,會報找不到物化檢視日誌,但是此時物化檢視的最後重新整理時間也會修改。
SQL> create materialized view log on t_mv;
Materialized view log created.
SQL> exec dbms_mview.refresh('MV_1','F');
BEGIN dbms_mview.refresh('MV_1','F'); END;
*
ERROR at line 1:
ORA-12034: materialized view log on "TY"."T_MV" younger than last refresh
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2563
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2776
ORA-06512: at "SYS.DBMS_SNAPSHOT", line 2745
ORA-06512: at line 1
物化檢視日誌時間不能小於物化檢視的最後重新整理時間。當我們重新建立物化檢視日誌,此時物化檢視日誌時間為4000-01-01 00:00:00,但是物化檢視的最後重新整理時間為06-MAY-12 01:48:41,此時就會報ORA-12034: materialized view log younger than last refresh。
==========End========================================================

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

相關文章