摘要:《Materialized Views 專案實作經驗》
2010/2/17
這邊講述專案實作的經驗。
狀況描述:
此專案要在一個接近4000萬筆資料、5.5 G左右的資料表,尋找特定的資料 (約莫 55萬筆資料,占1.3%資料量),此專案會經常性存取
(尖峰時間估計一分鐘內會有30次查詢)
這些特定資料作為業務上判斷需要,如果條件範圍較大時,因為索引及其它參考資料的存取,從原始資料取得必會耗費較多資源,
在經常性存取的情形下如同雪上加霜。
評估階段:
一開始評估時,直接將SQL寫好(串了許多資料表,還有union all)建置mview,後來受限於多個資料表的關係,mview類型屬於
4.Complex Materialized Views,
此種mview 在refresh時會重新執行SQL重新建置mview的資料,撈資料過於費時且占用許多buffer cache,雖然是離峰時間作業,
也不想在半夜把資料庫弄垮吧。
原本一度要放棄 mview 的作法,改採用程式運作,定時同步資料。
但在同事的建議下,重新評估了一次,這次對主要的資料表分別作 mview,mview 類型屬於 3.ROWID Materialized Views ,
可以加上 Materialized View log,加快refresh的速度,測試結果每天同步一次約 2 分鐘即可完成,再用 view 將其它資料表串起來。
因為主要資料表每天約有數十萬筆資料,考慮到資料庫的資源耗用情形,若即時同步資料,每一筆資料在DML時,除了要維護索引,
還要維護 mview,對資料庫資源也是不小的支出,且專案也不需要到即時資料,故在專案一開始即已表明,每天僅在半夜兩點時同步一次。
DDL 指令如下:
create materialized view log on mview_test tablespace mvdat with rowid;
create materialized view mview_test_mv tablespace mvdat REFRESH fast with rowid START WITH TRUNC(SYSDATE)+1/12 NEXT
RUNC(SYSDATE + 1)+1/12 as
select * from mview_test where F1 in ('A','C','D','Z');
實驗數據:
同樣結果下,直接存取來源資料表統計值如下:
統計值
----------------------------------------------------------
3967 recursive calls
0 db block gets
11685 consistent gets
373 physical reads
0 redo size
1474 bytes sent via SQL*Net to client
503 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
15 rows processed
同樣結果下,直接存取篩選過的mview資料表統計值如下:
統計值
----------------------------------------------------------
181 recursive calls
0 db block gets
1245 consistent gets
85 physical reads
0 redo size
1847 bytes sent via SQL*Net to client
503 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
15 rows processed
很明顯 physical reads 的數量減少許多,差異近300個data block,約莫1.2MB (範例資料庫為 db_block_size=4096);
此為單一案例,同上所述若經常性查詢,這差異就十分顯著。
-------------------------------------------------------------------------------
2012-04-11 更新
ps. 如果來源資料表欄位長度變更, 會造成 MATERIALIZED VIEW 無法更新同步
在 DBA_MVIEWS.STATUS 會出現 COMPLICATION_ERROR.
最後解決方式是重建 MVIEW
(
DROP MATERIALIZED VIEW KFSYSCC.MEDBROW_MV;
DROP MATERIALIZED VIEW LOG ON KFSYSCC.MEDBROW;
create materialized view log on kfsyscc.MEDBROW tablespace mvdat with rowid;
CREATE MATERIALIZED VIEW "KFSYSCC"."MEDBROW_MV" TABLESPACE "MVDAT" PCTFREE 10 INITRANS 1 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) NOLOGGING USING INDEX TABLESPACE "USERS" PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K BUFFER_POOL DEFAULT) REFRESH FORCE WITH ROWID ON COMMIT AS SELECT "MEDBROW"."CHART_NO" "CHART_NO","MEDBROW"."CHART_TYPE" "CHART_TYPE","MEDBROW"."VOL_NO" "VOL_NO","MEDBROW"."REASON" "REASON","MEDBROW"."LOCATION" "LOCATION","MEDBROW"."APL_EMPID" "APL_EMPID","MEDBROW"."RTN_DATE" "RTN_DATE","MEDBROW"."APL_OP_EMPID" "APL_OP_EMPID","MEDBROW"."APL_DATE" "APL_DATE","MEDBROW"."APL_TIME" "APL_TIME","MEDBROW"."OUT_EMPID" "OUT_EMPID","MEDBROW"."OUT_DATE" "OUT_DATE","MEDBROW"."OUT_TIME" "OUT_TIME","MEDBROW"."IN_EMPID" "IN_EMPID","MEDBROW"."IN_DATE" "IN_DATE","MEDBROW"."IN_TIME" "IN_TIME","MEDBROW"."SHELF_EMPID" "SHELF_EMPID","MEDBROW"."SHELF_DATE" "SHELF_DATE","MEDBROW"."SHELF_TIME" "SHELF_TIME" FROM "MEDBROW" "MEDBROW" WHERE "MEDBROW"."IN_DATE" IS NULL;
)