在執(zhí)行一個查詢時,優(yōu)化器會判定訪問物化視圖或數(shù)據(jù)駐留的基礎(chǔ)表是否更快一些。如果優(yōu)化器判定查詢物化視圖是更好的解決方案,那么優(yōu)化器會在一個被稱為“查詢改寫”(query rewrite)的過程中改寫SQL查詢。在這個過程中,不需要對任何SQL或應(yīng)用程序代碼進(jìn)行修改,所以任何利用SQL訪問數(shù)據(jù)庫的應(yīng)用程序或特定查詢工具都可得益于使用物化視圖。當(dāng)為計算結(jié)果而需要訪問的數(shù)據(jù)數(shù)量遠(yuǎn)大于結(jié)果(如集合)的大小時,最適合使用查詢改寫,但是它也可被用于加速昂貴的聯(lián)接或規(guī)劃。
本文首先介紹了優(yōu)化器可以執(zhí)行的查詢改寫類型。然后,它討論了幫助確定創(chuàng)建最佳物化視圖集的工具,使優(yōu)化器能夠改寫多個查詢。利用這些工具創(chuàng)建的物化視圖在其基礎(chǔ)數(shù)據(jù)發(fā)生變化時還可以快速刷新。如果你不知道創(chuàng)建一個物化視圖、一個索引或同時創(chuàng)建兩者哪種更好,那么在Oracle數(shù)據(jù)庫10g中引入的SQL Access Advisor可以通過分析給定的工作負(fù)荷幫助你做出決定。
查詢改寫類型
可能有許多類型的查詢改寫;當(dāng)物化視圖的定義查詢與查詢的文本完全匹配時,就發(fā)生最簡單和最顯著類型的查詢改寫。但是,當(dāng)相同物化視圖可用于相應(yīng)多個查詢時,就可以實現(xiàn)查詢改寫的最大好處。現(xiàn)在,我們將舉例說明一些Oracle優(yōu)化器使用的規(guī)則,以確定它是否將使用物化視圖來響應(yīng)。
對于本文中的示例,可以考慮將一個星形模式中的PURCHASES表看作事實表(fact table),其范圍由time_key劃分。維度表(dimension table)--TIME、PRODUCT和CUSTOMERS--包含主鍵 time_key、product_id和cust_id。在PURCHASES表中有引用各個維度表的外鍵約束。
考慮一下清單 1中所創(chuàng)建的物化視圖,該視圖按月按product_id計算銷售總額和銷售總次數(shù)。注意:對于用于查詢改寫的物化視圖,必須有ENABLE QUERY REWRITE子句。還有,初始化參數(shù)QUERY_REWRITE_ENABLED必須被設(shè)置為TRUE。
代碼清單 1:創(chuàng)建月銷售物化視圖
|
集合計算
在本文的示例中,我們將說明物化視圖的查詢并顯示由EXPLAIN PLAN得到的執(zhí)行計劃。清單 2中的查詢要求按月和按產(chǎn)品的平均采購價格。優(yōu)化器可以使用物化視圖monthly_sales_mv,利用SUM和COUNT集合計算平均采購價格。這個示例說明了一種叫做“集合計算”的技術(shù)。
代碼清單 2:獲得平均(AVG)采購價格
|
Joinback
Joinback技術(shù)非常有用,因為它允許當(dāng)物化視圖中沒有列時進(jìn)行查詢改寫。清單 3中的查詢要求按月和按產(chǎn)品類別的銷售總額,而該物化視圖中并沒有product.category列。然而,產(chǎn)品表的主鍵product_id列則位于物化視圖中。因此,優(yōu)化器可以將物化視圖與產(chǎn)品表聯(lián)接起來以得到產(chǎn)品類別。
代碼清單 3:通過joinback獲得銷售總額
|
使用維度進(jìn)行查詢改寫
在一個使用維度建模技巧設(shè)計的典型數(shù)據(jù)倉庫中,數(shù)據(jù)中存在著著名的“層次關(guān)系”。例如,在時間層次中,“天”積累成“月”,“月”又積累成“年”。在Oracle數(shù)據(jù)庫中,可以使用CREATE DIMENSION語句創(chuàng)建一個叫做“DIEMNSION”的對象,向優(yōu)化器聲明這種關(guān)系。維度對象是一個描述性對象,除了其元數(shù)據(jù)外,它不占用空間。使用DIMENSION對象聲明的關(guān)系據(jù)說是可信的。Oracle不會驗證這一關(guān)系對于你的數(shù)據(jù)是否一定成立,它只是假設(shè)數(shù)據(jù)庫管理員已經(jīng)判定這些關(guān)系是正確的。可信信息的其他示例是使用NOVALIDATE RELY標(biāo)記的約束及注冊為物化視圖的先存表。
對于采用可信信息(包括維度)的查詢改寫,初始化參數(shù)QUERY_ REWRITE_INTEGRITY必須被設(shè)置為TRUSTED,如下所示:
|
例如,假設(shè)有一個時間維度,其聲明如下:
|
現(xiàn)在,如果具有清單 4中要求按年的銷售額的查詢,你仍然可以使用monthly_sales_mv物化視圖,因為維度對象中的HIERARCHY子句告訴Oracle數(shù)據(jù)庫月銷售額可以積累成年銷售額。它利用前面描述的joinback技巧由物化視圖中的“月”列得到“年”列的值。
代碼清單 4:通過joinback和HIERARCHY獲得銷售總額
|
維度的ATTRIBUTE子句指明了一對一關(guān)系。例如,你可以判定從time_key開始是一周中的哪一天。假設(shè)你希望得到每年1月份的銷售總額:你仍然可以使用清單 5中所示的monthly_sales_mv物化視圖。注意該查詢的WHERE子句如何具有一個在物化視圖中沒有出現(xiàn)的選擇條件。
代碼清單 5:通過joinback和ATTRIBUTE獲得銷售總額
|
如果優(yōu)化器并未如期改寫一個查詢,你可以使用DBMS_MVIEW .EXPLAIN_REWRITE 過程來診斷此問題。注釋:這一特性出現(xiàn)在Oracle9i數(shù)據(jù)庫及以后的版本中。