" 1、視圖理論 " "1.1、視圖的存儲" "1.2、視圖的作用" "1.3、視圖的工作機制" "1.4、視圖的依賴性" "1.5、可更新的連接視圖" "1.6、內聯視圖" " 2、物化視圖 " "2.1、刷新物化視圖" "2.2、物化視圖日誌" "2.3、管理物化視圖" "2.4、物化視圖與索引 ...
我曾遇到一個項目的資料庫中視圖比表還要多很多(表和視圖加起來上千個),幾乎每個表都有對應的視圖,而且有很多視圖長得相似,比如有些視圖關聯的表一樣,只是查詢列表多或少了一兩個欄位。我敢斷定,這就是因為一些水平低劣的開發人員看現有表或視圖的數據不完全符合他的需要,就不假思索的拷貝過來改一下然後創建一個新的視圖完事兒,久而久之,自然會出現很多相似甚至相同的視圖。
在接手上述項目後,真正令我感到崩潰的是,查詢語句往往涉及多個視圖,且常常是相似的視圖定義中又引用了另一個相似的視圖,被引用的視圖中又引用了另一個相似的視圖……。總之就一個字——亂!有時候為了找與頁面上欄位對應的資料庫欄位得看完一堆的視圖定義才能找到,因此那段時間我特別厭惡視圖!並暗下決心:日後如果我能做主,絕不用視圖。
後來我換了公司,新接觸的項目資料庫中基本沒用視圖。結果沒過多久,我便發現代碼中有很多相似甚至重覆的查詢語句,而且代碼中的查詢語句改起來也比較費勁,於是乎我對視圖的主觀意識發生了搖擺。我開始問自己:到底該不該用視圖?如果用,要怎麼用才合理?用了視圖到底會降低性能還是會提升性能?
最後我通過閱讀《Oracle Database Concepts》並反覆實踐和揣摩,終於對視圖有所感悟。多學一點知識就少一點困惑,而我正是對視圖理論方面有了大致瞭解後才解開對視圖的各種困惑。本文第 1 節大部分內容是對官方手冊的簡化翻譯,也夾雜了一些我個人的體會,英語好的讀者也可以忽略本節直接閱讀原文。
1、視圖理論
視圖是對一或多個表或其他視圖中包含的數據的自定義呈現。視圖將查詢的輸出視為一個表,因此可以認為視圖就是存儲的查詢或虛擬表。視圖中包含行和列,就像一個真實的表,但不包含數據本身。視圖所引用的表被稱為基表,視圖總是呈現基表中最近的數據,視圖可支持更新數據,所有對視圖數據的更新都將被反映到視圖的基表中,並受到基表的完整性約束和觸發器的約束。
1.1、視圖的存儲
與表不同,視圖不需要分配存儲空間,視圖也不包含實際數據。視圖由查詢定義,該查詢從視圖基表中提取或導出數據。因為視圖是基於其他對象的,所以視圖只需要在數據字典中存儲定義視圖的查詢,而不需要額外的存儲空間。
1.2、視圖的作用
可通過視圖以不同的形式來顯示基表中的數據,而視圖的強大之處在於它能夠根據不同的用戶需求來對基表中的數據進行不同形式的整合。視圖的常見用途如下:
- 1、通過限制對基表中一組指定行或列的訪問,來提供額外的安全控制。
- 2、視圖允許通過表連接整合多個表中的相關行或列,構成一個新的數據集,從而達到隱藏數據複雜性的目的。
- 3、視圖提供了從多個表中查詢數據,而不必知道如何關聯這些表的可能,因而簡化了查詢的 SQL 語句。
- 4、重命名視圖的列或更改數據形式,不會影響視圖所引用的基表,這樣一來就能以不同的角度來呈現基表中的數據了。
- 5、保存複雜的查詢,一個查詢可能會對錶數據進行複雜的計算,如果將這個查詢保存為視圖,那之後需求進行計算只需查詢該視圖即可。
- 6、表達不使用視圖無法表達的查詢,有時候用戶需求過於複雜,幾乎寫不出來僅從基表中查詢數據的單條 SQL 語句,如某些複雜的分組查詢、聯合查詢等。
簡單來說,合理運用視圖,不僅可以提高數據的安全性,還可以少寫代碼,提升開發效率和程式的可維護性,也有利於在某些情況下靈活高效的控制數據的展現形式。
1.3、視圖的工作機制
Oracle 將定義視圖的語句以文本的形式存儲在數據字典中。當用戶在 SQL 語句中引用了視圖時,Oracle 將完成以下三步動作:
- 1、將引用了視圖的語句與視圖的定義語句合併成一個語句。
- 2、在共用 SQL 區解析整合後的語句。
- 3、執行該語句。
如果共用 SQL 區中存在相似語句,Oracle 就不會重覆解析,只有在共用 SQL 區中沒有相似語句時,Oracle 才會為該語句創建新的共用 SQL 區。因此引用了視圖的 SQL 語句也可能會節約記憶體進而提高查詢性能。
1.4、視圖的依賴性
定義視圖的查詢必須要引用其它對象(表、視圖),換而言之,視圖依賴於其所引用的對象而存在。Oracle 會自動地處理視圖的依賴關係。例如,當用戶刪除視圖的某個基表後再次創建它,Oracle 就會自動的去檢查新的基表是否符合現有的視圖定義,進而判斷視圖的有效性。在 PL/SQL Developer 中,所有 Oracle 認為無效的視圖都會被打上紅叉叉。
1.5、可更新的連接視圖
連接視圖是指在視圖定義的查詢的 FROM 字句中引用了多個表或視圖的視圖,而可更新的連接視圖是指能夠支持 UPDATE、INSERT 和 DELETE 操作的連接視圖。數據字典視圖ALL_UPDATABLE_COLUMNS
、DBA_UPDATABLE_COLUMNS
和USER_UPDATABLE_COLUMNS
中包含了那些可更新的視圖列信息。如果要確保視圖可更新,那麼視圖定義中就不能包含以下語法結構:
- 1、集合運算符。
- 2、DISTINCT 運算符。
- 3、聚合函數或分析函數。
- 4、GROUP BY、ORDER BY、CONNECT BY 或 START WITH 子句。
- 5、SELECT 列表中的集合表達式。
- 6、SELECT 列表中的子查詢。
- 7、JOIN 連接(也有例外情況)。
如果視圖只引用了一個表,且包含該表的主鍵,一般就可以對視圖進行 DML 操作。對於不支持 DML 操作的視圖,如包含上述語法結構的連接視圖,還可以使用 INSTEAD OF 觸發器來更新數據。INSTEAD OF 觸發器也被譯作替代觸發器,由於替代觸發器的特殊性,它永遠都是在操作執行前被觸發。語法如下:
CREATE [OR REPLACE] TRIGGER trg_name
INSTEAD OF [[INSERT] [OR UPDATE | UPDATE OF 列名[,列表,...]] [OR DELETE]] ON schema.v_name
[FOR EACH ROW]
[WHEN 觸發條件]
[DECLARE]
[聲明變數部分;]
BEGIN
IF INSERTING THEN
-- TODO: 添加
ELSIF UPDATING THEN
-- TODO: 修改
ELSIF DELETING THEN
-- TODO: 刪除
ELSE
NULL;
END IF;
END [trg_name];
1.6、內聯視圖
內聯視圖不是模式對象,而是一個有別名的子查詢,一般定義在 FROM 字句之後,可以在 SQL 語句中像使用普通視圖一樣的使用。內聯視圖是一種臨時視圖,不會存儲到數據字典中,它和標準視圖的主要區別是:不需要在執行 SQL 語句之前進行解析和創建共用 SQL 區。
2、物化視圖
物化視圖是包含查詢結果的資料庫對象,用於彙總、計算、複製及分發數據。物化視圖能夠預先計算並保存表連接或聚集等耗時較多的操作結果,這樣,在執行查詢時,就可以避免進行這些耗時的操作,從而快速的得到結果。物化視圖是一種特殊的物理表,“物化”視圖是相對普通視圖而言的。普通視圖是虛擬表,應用的局限性大,任何對視圖的查詢,Oracle 都實際上轉換為視圖 SQL 語句的查詢,這樣對整體查詢性能的提高,並沒有實質上的好處。
2.1、刷新物化視圖
Oracle 在對主表進行 DML 操作之後,會通過刷新來維護物化視圖中的數據(以確保物化視圖和基表中的數據同步)。刷新模式有兩種:ON DEMAND 和 ON COMMIT,而刷新方式有四種:FAST、COMPLETE、FORCE 和 NEVER。FAST 刷新採用增量刷新,只刷新自上次刷新以後進行的修改。COMPLETE 刷新對整個物化視圖進行完全的刷新。如果選擇FORCE 方式,Oracle 會在刷新前先判斷下是否可以進行快速刷新,如果可以則採用 FAST 刷新,否則採用 COMPLETE 刷新。NEVER 指物化視圖不進行任何刷新。
對於使用快速刷新方法的物化視圖,物化視圖日誌或直接載入日誌將保留對主表的更改記錄。已經創建好的物化視圖也還可以再修改它的刷新方式。物化視圖還可以按要求定期刷新。
2.2、物化視圖日誌
物化視圖日誌是將更改同步到主表的模式對象。通過物化視圖日誌可以逐級刷新主表上定義的物化視圖,此過程被稱為增量或快速刷新。如果沒有物化視圖日誌,Oracle 必須重新執行物化視圖查詢來刷新物化視圖,這個過程稱為完全刷新。通常,快速刷新比完全刷新需要更少的時間。
物化視圖日誌位於和主表相同模式中的主資料庫中。每個主表上最多能定義一個物化視圖日誌。Oracle 可以根據物化視圖日誌對所有需要快速刷新的物化視圖執行快速刷新。要快速刷新物化連接視圖,必須為實例化視圖引用的每個表創建一個物化視圖日誌。
創建物化視圖日誌:
示例一(創建支持主鍵實例化視圖快速刷新的物化視圖日誌,並指定物理和存儲特性):
CREATE MATERIALIZED VIEW LOG ON demo.t_staff
PCTFREE 5 -- 塊保留的空間百分比
TABLESPACE users
STORAGE (INITIAL 10K NEXT 10K);
示例二(創建支持快速刷新 ROWID 物化視圖和物化連接視圖的物化視圖日誌):
CREATE MATERIALIZED VIEW LOG ON demo.t_staff WITH PRIMARY KEY,ROWID;
示例三(創建支持快速刷新物化聚合視圖的物化視圖日誌):
CREATE MATERIALIZED VIEW LOG ON demo.t_staff
WITH ROWID, SEQUENCE(staff_id)
INCLUDING NEW VALUES;
更多創建物化視圖日誌的細節請參考:《Oracle Database SQL Reference: CREATE MATERIALIZED VIEW LOG》。修改物化視圖日誌的細節請參考:《Oracle Database SQL Reference: ALTER MATERIALIZED VIEW LOG》。
刪除物化視圖日誌:語法結構和刪除表相似,詳細請參考《Oracle Database SQL Reference: DROP MATERIALIZED VIEW》。
DROP MATERIALIZED VIEW LOG ON demo.t_staff;
2.3、管理物化視圖
創建物化視圖:
語法:
CREATE MATERIALIZED VIEW
[ schema. ]materialized_view
[ column_alias [, column_alias]... ]
[ OF [ schema. ]object_type ]
[ (scoped_table_ref_constraint) ]
{ ON PREBUILT TABLE
[ { WITH | WITHOUT } REDUCED PRECISION ]
| physical_properties materialized_view_props
}
[ USING INDEX
[ physical_attributes_clause
| TABLESPACE tablespace
]
[ physical_attributes_clause
| TABLESPACE tablespace
]...
| USING NO INDEX
]
[ create_mv_refresh ]
[ FOR UPDATE ]
[ { DISABLE | ENABLE }
QUERY REWRITE
]
AS subquery ;
示例一:
CREATE MATERIALIZED VIEW LOG ON demo.t_staff
WITH PRIMARY KEY
INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW mv_staff
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS SELECT t1.staff_id,t1.staff_name,DECODE(t1.gender,1,'男',0,'女','未知') gender
FROM demo.t_staff t1
WHERE t1.is_disabled=0;
示例二:
CREATE MATERIALIZED VIEW mv_staff2
AS SELECT t1.staff_id,t1.staff_name,DECODE(t1.gender,1,'男',0,'女','未知') gender,
EXTRACT(YEAR FROM SYSDATE)-EXTRACT(YEAR FROM t1.birthday) age
FROM demo.t_staff t1
WHERE t1.is_disabled=0;
更多創建物化視圖的細節請參考:《Oracle Database SQL Reference: CREATE MATERIALIZED VIEW》。修改物化視圖的細節請參考:《Oracle Database SQL Reference: ALTER MATERIALIZED VIEW》。
刪除物化視圖:語法結構和刪除表相似,詳細請參考《Oracle Database SQL Reference: DROP MATERIALIZED VIEW》。
DROP MATERIALIZED VIEW mv_staff2;
2.4、物化視圖與索引
物化視圖和索引都是為提高資料庫性能而存在的,所以它們有一定的相似之處。列舉如下:
- 1、它們都消耗存儲空間。
- 2、當主表中的數據發生更改時,都需要刷新。
- 3、當它們用於查詢時,都可以提高 SQL 執行的性能。
- 4、它們的存在對 SQL 應用程式和用戶是透明的(能看到且可以直接操作的意思)。
- 5、可以對它們進行分區。
物化視圖與索引不同點之一是:物化視圖可以在 SQL 語句中直接訪問,而索引是否生效取決於 Oracle 系統。
3、總結
本文主要講述了普通視圖的基本原理和物化視圖基本用法,希望能對讀者有所幫助。另外,由於我本人物化視圖用的也不多,所以講述的比較片面和淺顯,需要進一步瞭解的讀者可以再看看官網手冊:《Oracle Database Concepts: Overview of Materialized Views》。
本文鏈接:http://www.cnblogs.com/hanzongze/p/Oracle-View.html
版權聲明:本文為博客園博主 韓宗澤 原創,作者保留署名權!歡迎通過轉載、演繹或其它傳播方式來使用本文,但必須在明顯位置給出作者署名和本文鏈接!本人初寫博客,水平有限,若有不當之處,敬請批評指正,謝謝!