問題背景
描述
某省系統界面需要展示業務指標,該指標來自一張表如下圖所示,數據量巨大。舊方案的統計邏輯是:java cron定時任務執行sql匯總插入匯總表,匯總頻率一小時一次。
在進行定時匯總的時候,由於需要統計歷史所有數據,盡管sql已經優化避免全表掃描但是查詢sql執行時間很久。
導致:界面長時間沒數據。
限制因素
- 數據庫服務器配置一般,普通Pc配置(16g內存,500g硬盤,cpu不清楚),沒有ssd;
- 上集群、大數據分析、hadoop?想多了,估計沒人會(除了我,這里不謙虛了),運維成本比較高,客戶也不會給那么多機器;其實我還是很想搞這個實時計算的。
- 表沒有分區,如果分區可能會好點,重建表進行表分區,但是ogg可能要重新搭建;
- 不想改架構,把數據分表會好點,但是查詢邏輯要變化;
結合問題場景分析
- 每一小時都要把近幾年的歷史數據統計一遍,歷史數據又沒變化,真的有必要?
- 該指標也不需要做到有秒級的延遲,何況提供數據的友商一天才給2次數據,數據實時性也不高;
解決方案oracle物理視圖
**大道至簡:用空間換時間;這是數據結構與算法里面常見的解決方案。 **
也即:把不變動的歷史歷史數據都加工后存儲,定時匯總任務直接查加工后的數據,數據量大幅降低,提升查詢速度。雖然數據不是最新的,但是至少有數據可以容忍。
物化視圖概述
Oracle的物化視圖是包括一個查詢結果的數據庫對像,它是遠程數據的的本地副本,或者用來生成基於數據表求和的匯總表。
物化視圖可以用於預先計算並保存表連接或聚集等耗時較多的操作的結果,這樣,在執行查詢時,就可以避免進行這些耗時的操作,而從快速的得到結果。
物化視圖特點
- 使用物化視圖的目的是為了提高查詢性能;
- 物化視圖對應用透明,增加和刪除物化視圖不會影響應用程序中SQL語句的正確性和有效性;
- 物化視圖需要占用存儲空間;
- 當基表發生變化時,物化視圖也應當刷新。
這里我定的是物化視圖一天更新一次。
創建語法
CREATE MATERIALIZED VIEW XX
REFRESH [[fast | complete | force]
[on demand | commit]
[start with date]
[next date]
[with {primary key | rowid}]
]
[ENABLE | DISABLE] QUERY REWRITE
Refresh 刷新子句
描述 當基表發生了DML操作后,實體化視圖何時采用哪種方式和基表進行同步 。
- 取值 FAST 采用增量刷新,只刷新自上次刷新以后進行的修改 ;
- COMPLETE 對整個實體化視圖進行完全的刷新 ;
- FORCE(默認) Oracle在刷新時會去判斷是否可以進行快速刷新,如果可以則采用Fast方式,否則采用Complete的方式,Force選項是默認選項;
- ON DEMAND(默認) 實體化視圖在用戶需要的時候進行刷新,可以手工通過 DBMS_MVIEW.REFRESH等方法來進行刷新,也可以通過JOB定時進行刷新 ;
- ON COMMIT 實體化視圖在對基表的DML操作提交的同時進行刷新 ;
**START WITH 第一次刷新時間 **
**
**NEXT 刷新時間間隔 **
**
**WITH PRIMARY KEY(默認) **
生成主鍵實體化視圖,也就是說實體化視圖是基於表的主鍵,而不是ROWID(對應於ROWID子句)。 為了生成PRIMARY KEY子句,應該在表上定義主鍵,否則應該用基於ROWID的實體化視圖。主鍵實體化視圖允許識別實體化視圖表而不影響實體化視圖增量刷新的可用性
REWRITE 字句
**
包括ENABLE QUERY REWRITE和DISABLE QUERY REWRITE兩種。
分別指出創建的實體化視圖是否支持查詢重寫。查詢重寫是指當對實體化視圖的基表進行查詢時,Oracle會自動判斷能否通過查詢實體化視圖來得到結果,如果可以,則避免了聚集或連接操作,而直接從已經計算好的實體化視圖中讀取數據 默認 DISABLE QUERY REWRITE
demo
CREATE MATERIALIZED VIEW bm_dqd_znzdhs
refresh force on demand start with sysdate next trunc(sysdate+1)
as
select ksdm swjgdm ,
count(distinct djxh) znzdhs,
to_date(to_char(lrrq, 'YYYY-MM-DD'), 'YYYY-MM-DD') lrrq
from t_temp_ywtj_mx r
where ywlx = '自助' and ksdm is not null
group by ksdm, to_char(lrrq, 'YYYY-MM-DD');
參考
https://www.cnblogs.com/andy-wcl/p/3430995.html
感謝關注!