物化視圖是Oracle令人激賞的功能之一,在OLAP和OLTP系統都有廣泛應用。本系列文章對其進行由淺入深的案例講解。本文側重在最簡單的ON DEMAND和ON COMMIT物化視圖的討論。
【IT專家網獨家】
物化視圖是一種特殊的物理表,“物化”(Materialized)視圖是相對普通視圖而言的。普通視圖是虛擬表,應用的侷限性大,任何對視圖的查詢,Oracle都實際上轉換爲視圖SQL語句的查詢。這樣對整體查詢性能的提高,並沒有實質上的好處。
Oracle最早在OLAP系統中引入了物化視圖的概念。但後來很多大型OLTP系統中,發現類似統計的查詢是無可避免,而這些查詢操作如果很頻繁,對整體數據庫性能是很致命的。於是Oracle開始不斷的改進物化視圖,使得其也開始合適OLTP系統。從Oracle 8i到現在,功能已經相對比較完備了。
本文是Oracle物化視圖系列文章的第一篇,有兩個主要目的,來體驗一下創建ON DEMAND和ON COMMIT物化視圖的方法。ON DEMAND和ON COMMIT物化視圖的區別在於其刷新方法的不同,ON DEMAND顧名思義,僅在該物化視圖“需要”被刷新了,才進行刷新(REFRESH),即更新物化視圖,以保證和基表數據的一致性;而ON COMMIT是說,一旦基表有了COMMIT,即事務提交,則立刻刷新,立刻更新物化視圖,使得數據和基表一致。
1、第一個ON DEMAND物化視圖
1.1、創建ON DEMAND物化視圖
下面創建一個最簡單的物化視圖,這個物化視圖的定義很類似於普通視圖的創建語句,只是多了一個materialized,但就是這個單詞,造成了物化視圖和普通視圖(虛擬表)的天壤之別,也引申出後面很多的事情,呵呵。
本例中需要特別注意的是,Oracle給物化視圖的重要定義參數的默認值處理,在下面的例子中會有特別說明。因爲物化視圖的創建本身是很複雜和需要優化參數設置的,特別是針對大型生產數據庫系統而言。但Oracle允許以這種最簡單的,類似於普通視圖的辦法來做,所以不可避免的會涉及到默認值問題。
像我們這樣,創建物化視圖時未作指定,則Oracle按ON DEMAND模式來創建。
從下例中可以看出:
1) 物化視圖在某種意義上說就是一個物理表(而且不僅僅是一個物理表),這通過其可以被user_tables查詢出來,而得到佐證;
2) 物化視圖也是一種段(segment),所以其有自己的物理存儲屬性;
3) 物化視圖會佔用數據庫磁盤空間,這點從user_segment的查詢結果,可以得到佐證。
- 創建物化視圖
--獲取數據庫rdbms版本信息
SQL> select * from v$version; BANNER -------------------------------------------------------------------------------- Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production PL/SQL Release 11.1.0.6.0 - Production CORE 11.1.0.6.0 Production TNS for 32-bit Windows: Version 11.1.0.6.0 - Production NLSRTL Version 11.1.0.6.0 – Production |
SQL> create materialized view mv_testcf 2 as 3 select * from xiaotg.testcf; Materialized view created |
--分析物化視圖,以獲得統計信息
SQL> analyze table xiaotg.mv_testcf compute statistics; Table analyzed |
--查看物化視圖的行數,發現和master表(TESTCF)一樣
SQL> select tl.table_name, tl.num_rows from user_tables tl where tl.table_name in ( 'TESTCF', 'MV_TESTCF' ); TABLE_NAME NUM_ROWS ------------------------------ ---------- MV_TESTCF 80000 TESTCF 80000 |
--查看物化視圖的存儲參數
SQL> col segment_name for a24 SQL> select sg.segment_name, sg.bytes, sg.blocks from user_segments sg where sg.segment_name = 'MV_TESTCF'; SEGMENT_NAME BYTES BLOCKS ------------------------ ---------- ---------- MV_TESTCF 9437184 1152 |
- 查看物化視圖關鍵定義
--查看物化視圖的定義設置,請關注藍色字體部分。
--這表明,默認情況下,如果沒指定刷新方法和刷新模式,則Oracle默認爲FORCE和DEMAND。
--其他的集中刷新方法和刷新模式以後將分別予以介紹。
SQL> select mv.* from user_mviews mv where mv.MVIEW_NAME = 'MV_TESTCF';
(爲增加查詢結果的可讀性,下面進行了行列的互轉)
OWNERXIAOTG MVIEW_NAMEMV_TESTCF CONTAINER_NAMEMV_TESTCF QUERY QUERY_LEN80 UPDATABLEN UPDATE_LOG MASTER_ROLLBACK_SEG MASTER_LINK REWRITE_ENABLEDN REWRITE_CAPABILITYGENERAL REFRESH_MODEDEMAND REFRESH_METHODFORCE BUILD_MODEIMMEDIATE FAST_REFRESHABLEDML LAST_REFRESH_TYPECOMPLETE LAST_REFRESH_DATE2008-9-9 15:02 STALENESSFRESH AFTER_FAST_REFRESHFRESH UNKNOWN_PREBUILTN UNKNOWN_PLSQL_FUNCN UNKNOWN_EXTERNAL_TABLEN UNKNOWN_CONSIDER_FRESHN UNKNOWN_IMPORTN UNKNOWN_TRUSTED_FDN COMPILE_STATEVALID USE_NO_INDEXN STALE_SINCE NUM_PCT_TABLES0 NUM_FRESH_PCT_REGIONS NUM_STALE_PCT_REGIONS |
1.2、測試ON DEMAND物化視圖的更新特性
物化視圖最重要的功能和特性之一,就是其數據會隨着基表(或稱主表,master表,本例中爲TESTCF)的變化而變,基表數據增了,物化視圖數據會變多;基表數據刪了,物化視圖數據也會變少。
但怎麼更新?或者說物化視圖的數據怎麼隨着基表而更新?Oracle提供了兩種方式,手工刷新和自動刷新,像我們這種,在物化視圖定義時,未作任何指定,那當然是默認的手工刷新了。也就是說,通過我們手工的執行某個Oracle提供的系統級存儲過程或包,來保證物化視圖與基表數據一致性。
這是最基本的刷新辦法了。但所謂的自動刷新,其實也就是Oracle會建立一個job,通過這個job來調用相同的存儲過程或包,加以實現,這在本系列文章的第2篇會將以詳細闡述。
下面將測試INSERT,UPDATE和DELETE的測試方法類似,大家有興趣的話,可以自己試一試。
需要注意的是,下面暫不討論如何刷新ON DEMAND物化視圖,這是下一篇文章的內容。下面僅僅關注ON DEMAND物化視圖的特性及其和ON COMMIT物化視圖的區別,即前者不刷新(手工或自動)就不更新物化視圖,而後者不刷新也會更新物化視圖,——只要基表發生了COMMIT。
- 在基表插入測試數據
基表數據插入後,會發現,物化視圖並不會隨之更新。
--檢查基表和物化視圖是否有80001這一行記錄。
SQL> col id for a10;
SQL> col name for a30;
SQL> select * from xiaotg.testcf t where t.id = 80001 ;
ID NAME
---------- ------------------------------
SQL> select * from xiaotg.mv_testcf t where t.id = 80001 ;
ID NAME
---------- ------------------------------
--插入測試數據80001
--這時發現,基表有數據,但物化視圖並沒有
SQL> insert into xiaotg.testcf 2 values ( 80001, 'xiaotg he he'); 1 row inserted SQL> commit; Commit complete |
1.2.2 測試物化視圖數據是否更新
從下面的實驗可以看出,物化視圖數據不會更新,即使等上1分鐘、1小時、或者1天。
關於如何使得ON DEMAND物化視圖數據被更新,參加本系列的第二篇文章哈:)
SQL> select * from xiaotg.testcf t where t.id = 80001 ; ID NAME ---------- ------------------------------ 80001 xiaotg he he SQL> select * from xiaotg.mv_testcf t where t.id = 80001 ; ID NAME ---------- ------------------------------ SQL> |
2、第一個ON COMMIT物化視圖
最簡單的ON COMMIT物化視圖的創建,和上面創建ON DEMAND的物化視圖區別不大。因爲ON DEMAND是默認的,所以ON COMMIT物化視圖,需要再增加個參數即可。
2.1 創建ON COMMIT物化視圖
- 創建物化視圖
需要注意的是,無法在定義時僅指定ON COMMIT,還得附帶個參數才行,本例中附帶refresh force,關於這個參數的意思,以後將加以闡述。
--創建ON COMMIT物化視圖
SQL> create materialized view mv_testcf2
2 refresh force on commit
3 as
4 select * from xiaotg.testcf;
Materialized view created
SQL>
--分析物化視圖和基表
SQL> analyze table xiaotg.mv_testcf2 compute statistics; Table analyzed SQL> analyze table xiaotg.testcf compute statistics; Table analyzed |
--查看當前基表和物化視圖的行數
SQL> select tl.table_name, tl.num_rows from user_tables tl where tl.table_name in ( 'TESTCF', 'MV_TESTCF2' ); TABLE_NAME NUM_ROWS ------------------------------ ---------- MV_TESTCF2 80000 TESTCF 80000 |
- 查看物化視圖關鍵定義
可以從DBA_MVIEWS中看出,刷新模式爲COMMIT,這也是它和上面ON DEMAND物化視圖的唯一區別。
SQL> select mv.* from user_mviews mv where mv.MVIEW_NAME = 'MV_TESTCF'; |
(爲增加查詢結果的可讀性,下面進行了行列的互轉,且只顯示前三個關鍵列的)
REFRESH_MODECOMMIT REFRESH_METHODFORCE BUILD_MODEIMMEDIATE |
2.2 測試ON COMMIT物化視圖的更新特性
ON COMMIT物化視圖會在基表一旦提交時,就會立刻更新物化視圖本身,而且一般僅在物化視圖數據也被更新後,基表數據纔會事實的提交。
這意味着,這種模式可能會導致延遲基表數據的提交。。這點在下面的實驗中體現得很清楚。
實驗中,對基表TESTCF,平常的COMMIT在0.01秒內可以完成,但在有了ON COMMIT視圖MV_TESTCF2後,居然要6秒。速度減低了很多倍。ON COMMIT視圖對基表的影響可見一斑。
- 在基表中插入數據
SQL> set timing on; SQL> insert into xiaotg.testcf ( id, name ) values ( 80002, ' xiaotg again he he '); 1 row inserted Executed in 0.015 seconds SQL> commit; Commit complete Executed in 6.985 seconds SQL> select * from xiaotg.testcf where id = 80002; ID NAME --------------------------------- -------------------------------------------------------------------------------- 80002 xiaotg again he he Executed in 0 seconds SQL> col id for a10; SQL> col name for a40; SQL> select * from xiaotg.testcf where id = 80002; ID NAME ---------- ---------------------------------------- 80002 xiaotg again he he Executed in 0.016 seconds SQL> select * from xiaotg.mv_testcf2 where id = 80002; ID NAME ---------- ---------------------------------------- 80002 xiaotg again he he Executed in 0.031 seconds |
- 測試基表正常情況下的COMMIT速度
SQL> drop materialized view mv_testcf2; Materialized view dropped Executed in 1.984 seconds SQL> SQL> SQL> insert into xiaotg.testcf ( id, name ) values ( 80003, ' xiaotg again he he 3 '); 1 row inserted Executed in 0 seconds SQL> commit; Commit complete Executed in 0 seconds |