物化視圖與物化視圖日誌

【摘要】

            今天巡檢數據庫發現存在一張220G的數據庫實體表,通過命名(MLOG$_TABLE_NAME)可以看出這是一張物化視圖日誌表,基表只有120M,正常情況下物化視圖日誌會在物化視圖刷新後被數據庫自動清理,這裏的刷新無視刷新規則,fast、complete和force都會導致日誌被清空。

【正文】

            基表,物化視圖日誌和物化視圖關係

            一般情況下,創建物化視圖會直接從基表取數據,如果數據量比較大每次都全量獲取數據會對數據庫造成一定壓力,爲了能夠增量獲得基表的變化,可以考慮創建物化視圖日誌,物化視圖日誌根據基表主鍵產生記錄,每次基表發生DML操作都會產生一條或多條記錄,物化視圖可以根據這些記錄做到增量刷新,刷新完成後Oracle會自動清空物化視圖日誌。

            經過實驗,發現以下注意點

  1. 創建物化視圖日誌必須要求基表存在主鍵
  2. 創建物化視圖會自動刷新並清空物化視圖日誌
  3. user_registered_mviews視圖中的can_use_log默認爲yes,即使改爲no也可以使用並清空物化視圖日誌
  4. 如果修改基表定義導致物化視圖狀態爲INVALID,但是又改回原定義,此時的物化視圖在下次執行後會自動改爲VALID狀態
  5. 如果物化視圖日誌因其他原因導致很大,需要手動清理,可以通過Oracle自帶存儲過程(purge_mview_from_log)進行處理

具體語法:

exec dbms_mview.purge_mview_from_log(21);

--21爲mviews_id,從dba_base_table_mviews得到

物化視圖未及時更新,物化視圖日誌又被手動清理後,再次刷新物化視圖會導致報錯,此時需要重建物化視圖

ORA-12034: materialized view log on "owner"."table_name" younger than last refresh

            以下爲實驗步驟

create table t_mv (id int,name varchar2(20),age int);--創建測試表

alter table t_mv add constraint  pk_id primary key(id);--添加主鍵

create materialized view log on t_mv;--創建物化視圖日誌

select * from MLOG$_T_MV; --空

insert into t_mv values (1,'lpp',26);

commit;

select * from t_mv;--1條數據

select * from MLOG$_T_MV;--1條數據

select * from user_registered_mviews; --空

create materialized view mv_t_mv refresh fast as select id,name from t_mv;

select * from mv_t_mv;--1條數據;

select * from MLOG$_T_MV; --空, 創建時就會清空日誌表

insert into t_mv values (2,'lppe',26);

commit;

select * from t_mv;--2條數據

select * from MLOG$_T_MV;--1條數據,

select * from user_registered_mviews; --1條數據,can_use_log字段默認是yes

execute dbms_mview.refresh('mv_t_mv');--命令行執行

select * from mv_t_mv;--2條數據

select * from MLOG$_T_MV;--空

update user_registered_mviews set can_use_log='NO';--普通用戶無權限,sysdba提示不能修改虛擬列

select * from user_registered_mviews; --1條數據,can_use_log字段默認是no,通過修改基表SYS.REG_SNAP$

insert into t_mv values (3,'lppf',26);

commit;

select * from t_mv;--3條數據

select * from MLOG$_T_MV;--1條數據

execute dbms_mview.refresh('mv_t_mv');--命令行執行

select * from mv_t_mv;--3條數據

select * from MLOG$_T_MV;--空,can_use_log字段是no依然可以讀取並清空物化視圖日誌

alter table t_mv drop column name; --修改表定義,刪除name字段

select * from all_objects where object_name='MV_T_MV';--物化視圖狀態失效

alter table t_mv add name varchar2(20);--修改表定義,添加name字段

select * from all_objects where object_name='MV_T_MV';--物化視圖狀態依然失效

select * from dba_mviews;--上次刷新時間 2020/1/5 6:38:26,staleness 字段爲NEEDS_COMPILE,服務器時間有誤

select * from dba_base_table_mviews;--上次刷新時間 2020/1/5 6:38:26,mview_id 21

insert into t_mv values (4,26,'lppg');--修改表定義導致字段順序調整

commit;

select * from t_mv;--4條數據

select * from MLOG$_T_MV;--1條數據

execute dbms_mview.refresh('mv_t_mv');--命令行執行成功,此時發現物化視圖狀態爲有效

select * from mv_t_mv;--4條數據

select * from MLOG$_T_MV;--空,此時發現物化視圖狀態爲有效

alter table t_mv drop column name; --修改表定義,刪除name字段

select * from all_objects where object_name='MV_T_MV';--物化視圖狀態失效

insert into t_mv values (5,26);--刪除了name字段

select * from t_mv;--5條數據

select * from MLOG$_T_MV;--1條數據

execute dbms_mview.refresh('mv_t_mv');--命令行執行報錯 ORA-00904: "T_MV"."NAME": invalid identifier

insert into t_mv values (6,26);--刪除了name字段

select * from t_mv;--6條數據

select * from MLOG$_T_MV;--2條數據

insert into t_mv values (7,26);--刪除了name字段

select * from t_mv;--7條數據

select * from MLOG$_T_MV;--3條數據,不能刷新導致日誌一直增大,可能達到上百G

exec dbms_mview.purge_mview_from_log(21);--手動在命令行清理物化視圖日誌,從mview_id 21開始,21是從dba_base_table_mviews得到

select * from t_mv;--7條數據

select * from MLOG$_T_MV;--已清空

insert into t_mv values (8,26);--刪除了name字段

alter table t_mv add name varchar2(20);--修改表定義,添加name字段

execute dbms_mview.refresh('mv_t_mv');--命令行執行報錯 ORA-12034: materialized view log on "LPP"."T_MV" younger than last refresh

alter materialized view mv_t_mv compile;--嘗試編譯物化視圖,成功編譯

execute dbms_mview.refresh('mv_t_mv');--命令行執行報錯 ORA-12034: materialized view log on "LPP"."T_MV" younger than last refresh

drop materialized view mv_t_mv;--刪除物化視圖

create materialized view mv_t_mv refresh fast as select id,name from t_mv;--重建物化視圖

select * from mv_t_mv;--8條數據

select * from MLOG$_T_MV;--空

insert into t_mv values (9,26,'lpp');

select * from t_mv;--9條數據

select * from MLOG$_T_MV;--1條數據

alter materialized view mv_t_mv refresh force on demand;--修改刷新機制

execute dbms_mview.refresh('mv_t_mv');--命令行執行

select * from mv_t_mv;--9條數據

select * from MLOG$_T_MV;--空

drop materialized view mv_t_mv;--刪除物化視圖

insert into t_mv values (10,26,'lppa');

select * from t_mv;--10條數據

select * from MLOG$_T_MV;--1條數據

create materialized view mv_t_mv refresh force on demand as select id,name from t_mv;--重建物化視圖

select * from mv_t_mv;--9條數據

select * from MLOG$_T_MV;--空

drop materialized view mv_t_mv;--刪除物化視圖

insert into t_mv values (11,26,'lppb');

select * from t_mv;--11條數據

select * from MLOG$_T_MV;--1條數據

create materialized view mv_t_mv refresh complete on demand as select id,name from t_mv;--重建物化視圖

select * from mv_t_mv;--11條數據

select * from MLOG$_T_MV;--空

delete from t_mv where id=11; --1條數據

update t_mv set age=25; --11條數據

【總結】

            經常檢查數據庫無效對象,尤其是物化視圖是否失效,及時排查及時處理,避免浪費過多的空間。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章