【摘要】
今天巡檢數據庫發現存在一張220G的數據庫實體表,通過命名(MLOG$_TABLE_NAME)可以看出這是一張物化視圖日誌表,基表只有120M,正常情況下物化視圖日誌會在物化視圖刷新後被數據庫自動清理,這裏的刷新無視刷新規則,fast、complete和force都會導致日誌被清空。
【正文】
基表,物化視圖日誌和物化視圖關係
一般情況下,創建物化視圖會直接從基表取數據,如果數據量比較大每次都全量獲取數據會對數據庫造成一定壓力,爲了能夠增量獲得基表的變化,可以考慮創建物化視圖日誌,物化視圖日誌根據基表主鍵產生記錄,每次基表發生DML操作都會產生一條或多條記錄,物化視圖可以根據這些記錄做到增量刷新,刷新完成後Oracle會自動清空物化視圖日誌。
經過實驗,發現以下注意點
- 創建物化視圖日誌必須要求基表存在主鍵
- 創建物化視圖會自動刷新並清空物化視圖日誌
- user_registered_mviews視圖中的can_use_log默認爲yes,即使改爲no也可以使用並清空物化視圖日誌
- 如果修改基表定義導致物化視圖狀態爲INVALID,但是又改回原定義,此時的物化視圖在下次執行後會自動改爲VALID狀態
- 如果物化視圖日誌因其他原因導致很大,需要手動清理,可以通過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條數據
【總結】
經常檢查數據庫無效對象,尤其是物化視圖是否失效,及時排查及時處理,避免浪費過多的空間。