Oracle 查詢轉換

chenoracle發表於2020-03-13

Oracle® Database   SQL Tuning Guide

Part II Query Optimizer Fundamentals

--- 3   SQL Processing

--- 4   Query Optimizer Concepts

--- 5   Query Transformations

查詢轉換

5 Query Transformations

本章描述了用於轉換查詢的最重要的優化器技術。

優化器根據成本來決定是否使用可用的轉換。由於各種原因,包括 hints 提示或缺少約束,優化器可能無法使用轉換。例如,對於包含不支援約束的外部分割槽的混合分割槽表,不能使用諸如子查詢 展開 之類的轉換。

5.1  or (OR Expansion)

or 擴充套件中,優化器將包含頂級分隔符的查詢塊轉換為包含兩個或多個分支的UNION ALL 查詢的形式。

優化器通過將 操作 分解為 其他 元件,然後將每個元件與UNION ALL 查詢的一個分支關聯來實現這個目標。優化器可以根據各種原因進行選擇 OR 擴充套件。例如,它可以啟用更有效的訪問路徑或避免笛卡爾積的可選連線方法。與往常一樣,只有在轉換語句的成本低於原始語句的成本時,優化器才執行擴充套件。

在以前的版本中,優化器使用連線操作符來執行OR 擴充套件。從 Oracle 資料庫 12c 版本 2(12.2) 開始,優化器將使用 UNION-ALL 操作符。該框架提供了以下增強功能 :

•支援各種轉換之間的互動

•避免共享查詢結構

•允許探索各種搜尋策略

•提供成本註釋的重用

•支援標準的 SQL 語法

示例5-1   查詢 轉換 UNION ALL 條件

要準備此示例,請以管理員身份登入資料庫,執行以下語句以向

hr.departments.department_name 列新增唯一約束,然後向 hr.employees 表新增 100000 行:

ALTER   TABLE  hr.departments ADD   CONSTRAINT  department_name_uk UNIQUE   ( department_name );

DELETE   FROM  hr.employees WHERE  employee_id >   999 ;

DECLARE

  v_counter NUMBER ( 7 )   :=   1000 ;

BEGIN

   FOR  i IN   1  .. 100000   LOOP

     INSERT   INTO  hr.employees

     VALUES

       ( v_counter ,

        null ,

        'Doe' ,

        'Doe'   ||  v_counter ||   '@example.com' ,

        null ,

        '07-JUN-02' ,

        'AC_ACCOUNT' ,

        null ,

        null ,

        null ,

        50 );

    v_counter :=  v_counter +   1 ;

   END   LOOP ;

END ;

/

COMMIT ;  

EXEC  DBMS_STATS.GATHER_TABLE_STATS (  ownname =>   'hr' ,  tabname =>   'employees' );

然後以使用者hr 的身份連線,並執行以下查詢,該查詢將連線“ employees ”和“ departments ”表:

SELECT   *

   FROM  employees e ,  departments d

  WHERE   ( e.email =   'SSTILES'   OR  d.department_name =   'Treasury' )

    AND  e.department_id =  d.department_id ;

在沒有 OR 擴充套件 的情況下,優化器將e.email='SSTILES' d.department='Treasury' 視為一個單元。因此,優化器無法在 e.email d.department_name 列上使用索引,因此會對員工和部門執行全表掃描。

使用 OR 擴充套件,優化器將 OR 對應的 謂詞分解為兩個獨立的謂詞,如下例所示:

SELECT   *

   FROM  employees e ,  departments d

  WHERE  e.email =   'SSTILES'

    AND  e.department_id =  d.department_id

UNION   ALL

SELECT   *

   FROM  employees e ,  departments d

  WHERE  d.department_name =   'Treasury'

    AND  e.department_id =  d.department_id ;

此轉換使e.email d.department_name 列可以用作索引鍵。效能提高是因為資料庫使用兩個唯一索引而不是兩個完整表掃描來篩選資料,如下執行計劃所示:

5.2 檢視合併 (View Merging)

在檢視合併中,優化器將表示檢視的查詢塊合併到包含檢視的查詢塊中。

檢視合併可以通過允許優化器考慮附加的連線 順序 、訪問方法和其他轉換來改進計劃。例如,在合併了一個檢視並將多個表駐留在一個查詢塊中之後,檢視中的一個表可能允許優化器使用join elimination 來刪除檢視外的一個表。

對於某些簡單檢視,合併總是導致更好的計劃,優化器會自動合併檢視,而不考慮成本。否則,優化器將使用成本來確定。優化器可能出於許多原因(包括成本或有效性限制)選擇不合並檢視。

如果optimizer_secure_view_merge true( 預設值 ) ,那麼 Oracle 資料庫將執行檢查,以確保檢視合併和謂詞推送不會違反檢視建立者的安全意圖。要禁用針對特定檢視的這些附加安全檢查,可以將 MERGE VIEW 權授予此檢視的使用者。要禁用針對特定使用者的所有檢視的附加安全檢查,可以將 MERGE ANY VIEW 特權授予該使用者。

注意:

您可以使用提示來覆蓋由於成本或啟發而被拒絕的檢視合併,但不能覆蓋有效性。

5.2.1 檢視合併中的查詢塊

優化器通過一個單獨的查詢塊來表示每個巢狀的子查詢或未合併檢視。

資料庫分別自底向上優化查詢塊。因此,資料庫首先對最內部的查詢塊進行優化,為它生成計劃的一部分,然後為外部的查詢塊生成計劃,表示整個查詢。

解析器將查詢中引用的每個檢視擴充套件為一個單獨的查詢塊。塊本質上表示檢視定義,從而表示檢視的結果。優化器的一個選項是單獨分析檢視查詢塊,生成檢視子計劃,然後通過使用檢視子計劃生成總體執行計劃來處理查詢的其餘部分。但是,這種技術可能導致次優的執行計劃,因為檢視是單獨優化的。

檢視合併有時可以提高效能。如“例 5-2 ”所示,檢視合併將檢視中的表合併到外部查詢塊中,刪除內部查詢塊。因此,不需要對檢視進行單獨的優化。

5.2.2 簡單檢視合併

在簡單的檢視合併中,優化器合併select-project-join 檢視。

例如,對employees 表的查詢包含一個子查詢,它連線 department locations 表。

簡單檢視合併經常會導致更優的計劃,因為合併之後會有更多的 連線順序 和訪問路徑可用。一個檢視可能對簡單檢視合併無效,因為:

•檢視包含的結構不包括在 select-project-join 檢視中,包括 :

GROUP BY

DISTINCT

Outer join

MODEL

CONNECT BY

Set operators

Aggregation

•檢視出現在半連線或反連線的右側。

•檢視在 select 列表中包含子查詢。

•外部查詢塊包含 PL/SQL 函式。

•檢視參與外部連線,並且不滿足決定檢視是否可以合併的幾個附加有效性要求之一。

示例5-2 簡單檢視合併

下面的查詢將hr.employees 表與 dept_locs_v 檢視連線起來,後者返回每個部門的街道地址。 dept_locs_v 是“ departments locations ”表的聯接。

SELECT  e.first_name ,

       e.last_name ,

       dept_locs_v.street_address ,

       dept_locs_v.postal_code

   FROM  employees e ,

        ( SELECT  d.department_id ,

               d.department_name ,

               l.street_address ,

               l.postal_code

           FROM  departments d ,  locations l

          WHERE  d.location_id =  l.location_id )  dept_locs_v

  WHERE  dept_locs_v.department_id =  e.department_id

    AND  e.last_name =   'Smith' ;

資料庫可以執行前面的查詢,方法是連線departments locations 以生成檢視的行,然後將此結果連線到 employee 。由於查詢包含檢視 dept_locs_v ,並且此檢視包含兩個表,優化器必須使用以下聯接順序之一:

employees, dept_locs_v (departments, locations)

employees, dept_locs_v (locations, departments)

dept_locs_v (departments, locations), employees

dept_locs_v (locations, departments), employees

聯接方法也受到約束。基於索引的巢狀迴圈聯接不適用於以employees 開頭的聯接順序,因為此檢視的列上不存在索引。在不合並檢視的情況下,優化器生成以下執行計劃:

檢視合併將檢視中的表合併到外部查詢塊中,刪除內部查詢塊。檢視合併後,查詢如下:

SELECT  e.first_name ,  e.last_name ,  l.street_address ,  l.postal_code

   FROM  employees e ,  departments d ,  locations l

  WHERE  d.location_id =  l.location_id

    AND  d.department_id =  e.department_id

    AND  e.last_name =   'Smith' ;

由於這三個表都出現在一個查詢塊中,優化器可以從以下六個聯接順序中進行選擇:

employees, departments, locations

employees, locations, departments

departments, employees, locations

departments, locations, employees

locations, employees, departments

locations, departments, employees

employees departments 的連線現在可以基於索引。檢視合併後,優化器選擇以下更有效的計劃,該計劃使用巢狀迴圈:

5.2.3 複雜檢視合併

在檢視合併中,優化器合併包含GROUP BY DISTINCT 檢視的檢視。與簡單的檢視合併一樣,複雜的合併使優化器能夠考慮附加的連線順序和訪問路徑。

優化器可以延遲GROUP BY DISTINCT 操作的計算,直到計算完連線之後。根據資料特徵延遲這些操作可以提高或降低效能。如果連線使用篩選器,那麼將操作延遲到連線之後可以減少要執行操作的資料集。儘早評估操作可以減少後續連線要處理的資料量,或者連線可以增加操作要處理的資料量。優化器使用成本來評估檢視合併,並且僅在檢視是較低成本選項時才合併檢視。

除了成本,優化器可能無法執行復雜的檢視合併的原因如下:

•外部查詢表沒有 rowid 或唯一列。

•檢視出現在 CONNECT BY 查詢塊中。

•檢視包含分組集、 ROLLUP PIVOT 子句。

•檢視或外部查詢塊包含 MODEL 子句。

5-3 複雜檢視與 GROUP BY 連線

下面的檢視使用了一個GROUP BY 子句 :

CREATE   VIEW  cust_prod_totals_v AS

SELECT   SUM ( s.quantity_sold )  total ,  s.cust_id ,  s.prod_id FROM sales s

GROUP   BY  s.cust_id ,  s.prod_id ;

下面的查詢找到了所有購買了至少100 件毛邊毛衣的美國客戶 :

SELECT  c.cust_id ,  c.cust_first_name ,  c.cust_last_name ,  c.cust_email

   FROM  customers c ,  products p ,  cust_prod_totals_v

  WHERE  c.country_id =   52790

    AND  c.cust_id =  cust_prod_totals_v.cust_id

    AND  cust_prod_totals_v.total >   100

    AND  cust_prod_totals_v.prod_id =  p.prod_id

    AND  p.prod_name =   'T3 Faux Fur-Trimmed Sweater' ;

cust_prod_totals_v 檢視適合複雜的檢視合併。合併後的查詢如下 :

SELECT  c.cust_id ,  cust_first_name ,  cust_last_name ,  cust_email

   FROM  customers c ,  products p ,  sales s

  WHERE  c.country_id =   52790

    AND  c.cust_id =  s.cust_id

    AND  s.prod_id =  p.prod_id

    AND  p.prod_name =   'T3 Faux Fur-Trimmed Sweater'

  GROUP   BY  s.cust_id ,

          s.prod_id ,

          p.rowid ,

          c.rowid ,

          c.cust_email ,

          c.cust_last_name ,

          c.cust_first_name ,

          c.cust_id

HAVING   SUM ( s.quantity_sold )   >   100 ;

轉換後的查詢比未轉換的查詢 成本更低 ,因此優化器選擇合併檢視。在未轉換的查詢中,GROUP BY 操作符應用於檢視中的整個 sales 表。在轉換後的查詢中,連線到 products customers 將過濾掉 sales 表中的大部分行,因此 GROUP BY 操作的成本更低。連線的開銷更大,因為 sales 表還沒有被縮減,但開銷也不 會特別 大,因為GROUP BY 操作並沒有很大程度地減少原始查詢中的行集大小。如果前面的任何特徵發生了變化,那麼合併檢視的成本可能就不再低了。不包括檢視的最終計劃如下 :

示例5-4 具有 DISTINCT 的複雜檢視連線

以下對cust_prod_v 檢視的查詢使用不同的運算子:

SELECT  c.cust_id ,  c.cust_first_name ,  c.cust_last_name ,  c.cust_email

   FROM  customers c ,

       products p ,

        ( SELECT   DISTINCT  s.cust_id ,  s.prod_id FROM  sales s )  cust_prod_v

  WHERE  c.country_id =   52790

    AND  c.cust_id =  cust_prod_v.cust_id

    AND  cust_prod_v.prod_id =  p.prod_id

    AND  p.prod_name =   'T3 Faux Fur-Trimmed Sweater' ;

在確定檢視合併會產生較低成本的計劃之後,優化器會將查詢重寫為此等效查詢:

SELECT  nwvw.cust_id ,

       nwvw.cust_first_name ,

       nwvw.cust_last_name ,

       nwvw.cust_email

   FROM   ( SELECT   DISTINCT   ( c.rowid ),

                        p.rowid ,

                        s.prod_id ,

                        s.cust_id ,

                        c.cust_first_name ,

                        c.cust_last_name ,

                        c.cust_email

           FROM  customers c ,  products p ,  sales s

          WHERE  c.country_id =   52790

            AND  c.cust_id =  s.cust_id

            AND  s.prod_id =  p.prod_id

            AND  p.prod_name =   'T3 Faux Fur-Trimmed Sweater' )  nwvw ;

上述查詢的計劃如下:

前面的計劃包含一個名為vm_nwvw_1 的檢視,稱為投影檢視,即使在檢視合併之後也是如此。投影檢視出現在合併了不同檢視的查詢中,或將逐檢視組合併到還包含 GROUP BY HAVING 或聚合的外部查詢塊中。在後一種情況下,投影檢視包含來自原始外部查詢塊的 GROUP BY HAVING aggregates

在前面的投影檢視示例中,優化器在合併檢視時,會將DISTINCT 運算子移到外部查詢塊,然後新增多個附加列以保持與原始查詢的語義等價。

之後,查詢只能在外部查詢塊的選擇列表中選擇所需的列。優化保留了檢視合併的所有好處:所有表都在一個查詢塊中,優化器可以根據需要按最終聯接順序排列它們,而 DISTINCT 操作被延遲到所有聯接完成之後。

5.3 謂詞推 ( Predicate Pushing)

在謂詞推 中,優化器將相關謂詞從包含查詢塊“推送”到檢視查詢塊中。

對於未合併的檢視,此技術改進了未合併檢視的子計您將建立一個引用employees contract_workers 的檢視。檢視是通過使用 UNION set 操作符的查詢定義的,如下所示 : 劃。資料庫可以使用推入式謂詞來訪問索引或用作篩選器。

例如,假設您建立一個表hr.contract_workers ,如下所示:

DROP   TABLE  contract_workers ;

CREATE   TABLE  contract_workers AS   ( SELECT   *   FROM  employees where   1 = 2 );  

INSERT   INTO  contract_workers VALUES   ( 306 ,   'Bill' ,   'Jones' ,   'BJONES' , '555.555.2000' ,   '07-JUN-02' ,   'AC_ACCOUNT' ,   8300 ,   0 , 205 ,   110 );

INSERT   INTO  contract_workers VALUES   ( 406 ,   'Jill' ,   'Ashworth' ,   'JASHWORTH' ,   '555.999.8181' ,   '09-JUN-05' ,   'AC_ACCOUNT' ,   8300 ,   0 , 205 ,   50 );

INSERT   INTO  contract_workers VALUES   ( 506 ,   'Marcie' ,   'Lunsford' ,   'MLUNSFORD' ,   '555.888.2233' ,   '22-JUL-01' ,   'AC_ACCOUNT' ,   8300 , 0 ,   205 ,   110 );

COMMIT ;

CREATE   INDEX  contract_workers_index ON  contract_workers ( department_id );

您將建立一個引用employees contract_workers 的檢視。檢視是通過使用 UNION set 操作符的查詢定義的,如下所示 :

CREATE   VIEW  all_employees_vw AS

(   SELECT  employee_id ,  last_name ,  job_id ,  commission_pct ,  department_id FROM employees )

UNION

(   SELECT  employee_id ,  last_name ,  job_id ,  commission_pct ,  department_id FROM contract_workers );

然後按如下方式查詢檢視:

SELECT  last_name FROM  all_employees_vw WHERE  department_id =   50 ;

因為檢視是一個UNION set 查詢,所以優化器不能將檢視的查詢合併到正在訪問的查詢塊中。相反,優化器可以通過將其謂詞 WHERE 子句 條件 department_id=50 推入檢視的 UNION set 查詢來轉換訪問語句。等價轉換查詢如下 :

SELECT  last_name

   FROM   ( SELECT  employee_id ,  last_name ,  job_id ,  commission_pct ,  department_id

           FROM  employees

          WHERE  department_id =   50

         UNION

         SELECT  employee_id ,  last_name ,  job_id ,  commission_pct ,  department_id

           FROM  contract_workers

          WHERE  department_id =   50 );

轉換後的查詢現在可以考慮在每個查詢塊中進行索引訪問。

5.4   子查詢 展開(Subquery Unnesting)

在子查詢 展開 中,優化器將巢狀查詢轉換為等效的連線語句,然後優化連線。

此轉換使優化器能夠在訪問路徑、連線方法和連線順序選擇期間考慮子查詢表。優化器只有在保證 子查詢展開和原始語句返回一樣的結果 ,並且子查詢不包含諸如AVG 之類的聚合函式的情況下才能執行此轉換。

例如,假設您以使用者sh 連線並執行以下查詢 :

SELECT   *   FROM  sales WHERE  cust_id IN   ( SELECT  cust_id FROM  customers );

由於customers.cust_id 列是主鍵,優化器可以將複雜查詢轉換為保證返回相同資料的以下連線語句:

SELECT  sales. *

   FROM  sales ,  customers

  WHERE  sales.cust_id =  customers.cust_id ;

如果優化器不能將複雜語句轉換成連線語句,它將選擇父語句和子查詢的執行計劃,就好像它們是獨立的語句一樣。然後優化器執行子查詢並使用返回的行來執行父查詢。為了提高整體執行計劃的執行速度,優化器可以有效地對子計劃進行排序。

5.5 物化檢視重寫查詢

---Query Rewrite with Materialized Views

物化檢視是儲存在表中的查詢結果。

當優化器發現使用者查詢與與物化檢視關聯的查詢相容時,資料庫可以根據物化檢視重寫查詢。該技術改進了查詢執行,因為資料庫已經預先計算了大部分查詢結果。

優化器尋找與使用者查詢相容的物化檢視,然後使用基於成本的演算法選擇物化檢視來重寫查詢。當生成計劃時,優化器不會重寫查詢,除非物化檢視的成本低於使用物化檢視生成的計劃。

5.5.1 關於查詢重寫和優化器

一個查詢要經過多次檢查,以確定它是否是查詢重寫的候選物件。

如果查詢沒有通過任何檢查,那麼查詢將應用於詳細表,而不是物化檢視。在響應時間和處理能力方面,不能重寫的代價可能很高。

優化器使用兩種不同的方法來確定何時根據物化檢視重寫查詢。第一個方法將查詢的SQL 文字與物化檢視定義的 SQL 文字匹配。如果第一個方法失敗,那麼優化器將使用更通用的方法,在該方法中比較查詢和物化檢視之間的連線、選擇、資料列、分組列和聚合函式。

查詢重寫操作查詢和子查詢在以下型別的SQL 語句 :

SELECT

CREATE TABLE AS SELECT

INSERT INTO SELECT

它還對 集合 操作符UNION UNION ALL INTERSECT INTERSECT ALL EXCEPT MINUS MINUS ALL 中的子查詢以及 INSERT DELETE UPDATE DML 語句中的子查詢進行操作。

維度、約束和重寫完整性級別影響是否將查詢重寫為使用物化檢視。此外,可以通過rewrite NOREWRITE 提示以及 QUERY_REWRITE_ENABLED 會話引數來啟用或禁用查詢重寫。

DBMS_MVIEW EXPLAIN_REWRITE 過程建議是否可以在一個查詢上重寫查詢,如果可以,則建議使用哪個物化檢視。它還解釋了為什麼不能重寫查詢。

5.5.2   關於查詢重寫的初始化引數

查詢重寫行為由某些資料庫初始化引數控制。

引數:QUERY_REWRITE_ENABLED

引數值:TRUE (default), FALSE, FORCE

查詢重寫行為: OPTIMIZER_MODE 設定為 FIRST_ROWS 的情況下,優化器使用成本和啟發式的混合來尋找快速交付前幾行的最佳計劃。當設定為 FIRST_ROWS_n 時,優化器使用基於成本的方法並以最佳響應時間為目標進行優化,以返回前 n 行(其中 n=1 10 100 1000 )。

引數:QUERY_REWRITE_ENABLED

引數值:TRUE (default), FALSE, FORCE

查詢重寫行為: 此選項啟用優化器的查詢重寫功能,使優化器能夠利用物化檢視來提高效能。如果設定為FALSE ,則此選項將禁用優化器的查詢重寫功能,並指示優化器不要使用物化檢視重寫查詢,即使未寫入查詢的估計查詢成本較低。

如果設定為FORCE ,則此選項將啟用優化器的查詢重寫功能,並指示優化器使用物化檢視重寫查詢,即使未寫入查詢的估計查詢成本較低。

引數:QUERY_REWRITE_INTEGRITY

引數值:STALE_TOLERATED,TRUSTED, or ENFORCED (the default)

查詢重寫行為: 此引數是可選的。但是,如果設定了該值,則該值必須是在“初始化引數值”列中指定的值之一。

預設情況下,完整性級別設定為ENFORCED ”。在此模式下,必須驗證所有約束。

因此,如果使用ENABLE NOVALIDATE relient ,某些型別的查詢重寫可能無法工作。若要在此環境中啟用查詢重寫(在未驗證約束的情況下),應將完整性級別設定為較低的粒度級別,如 TRUSTED STALE_TOLERATED

5.5.3 關於查詢重寫的準確性

查詢重寫提供了由初始化引數QUERY_REWRITE_INTEGRITY 控制的三層重寫完整性。

您可以為QUERY_REWRITE_INTEGRITY 引數設定的值如下 :

ENFORCED

這是預設模式。優化器只使用來自物化檢視的新資料,並且只使用基於已啟用的、有效的主鍵、惟一鍵或外來鍵約束的關係。

TRUSTED

在可信模式下,優化器相信在維度中宣告的關係和依賴約束是正確的。在此模式下,優化器還使用預構建的物化檢視或基於檢視的物化檢視,並使用未強制執行的關係和強制執行的關係。它還信任宣告但未啟用的、經過驗證的主鍵或惟一鍵約束以及使用維度指定的資料關係。此模式提供了更強大的查詢重寫功能,但如果您宣告的任何可信關係不正確,則會產生不正確結果的風險。

STALE_TOLERATED

STALE_TOLERATED 模式下,優化器使用的物化檢視是有效的,但是包含過時的資料,也包含新的資料。這種模式提供了最大的重寫能力,但會產生不準確結果的風險。

5.5.4 查詢重寫示例

這個示例演示了使用物化檢視重寫查詢的強大功能。

考慮下面的實體化檢視cal_month_sales_mv ,它提供了每月銷售金額的彙總 :

CREATE   MATERIALIZED   VIEW  cal_month_sales_mv ENABLE   QUERY   REWRITE   AS

SELECT  t.calendar_month_desc ,   SUM ( s.amount_sold )   AS  dollars

   FROM  sales s ,  times t

  WHERE  s.time_id =  t.time_id

  GROUP   BY  t.calendar_month_desc ;

讓我們假設,在一個典型的月份裡,商店的銷售額大約是一百萬。所以這個具體化的彙總檢視包含了每個月銷售金額的預先計算的彙總。

考慮下面的查詢,它要求商店每個日曆月的銷售額總和:

SELECT  t.calendar_month_desc ,   SUM ( s.amount_sold )

   FROM  sales s ,  times t

  WHERE  s.time_id =  t.time_id

  GROUP   BY  t.calendar_month_desc ;

在缺少前面的物化檢視和查詢重寫特性的情況下,Oracle 資料庫必須直接訪問 sales 表並計算已銷售的金額總和才能返回結果。這涉及到從 sales 表中讀取數百萬行,這將不可避免地由於磁碟訪問而增加查詢響應時間。查詢中的連線還將進一步降低查詢響應的速度,因為需要對數百萬行計算連線。

當實體化檢視cal_month_sales_mv 出現時,查詢重寫將透明地將之前的查詢重寫為以下查詢 :

SELECT  calendar_month ,  dollars FROM  cal_month_sales_mv ;

因為在物化檢視中只有幾十行 cal_month_sales_mv 沒有連線, Oracle 資料庫立即返回結果。

5.6 轉換 (Star Transformation)

星型轉換是一種優化器轉換,它避免了對星型模式中的事實表進行全表掃描。

5.6.1 關於星型模式

星型模式將資料分為事實和維度。

事實是對事件( 如銷售 ) 的度量,通常是數字。維度是標識事實的類別,例如日期、位置和產品。

事實表有一個由模式維度表的主鍵組成的組合鍵。維度表充當查詢或引用表,使您能夠選擇約束查詢的值。

關係圖通常顯示一箇中心事實表,其中的行將其連線到維度表,呈現星形的外觀。下面的圖形顯示銷售作為事實表,產品、時間、客戶和渠道作為維度表。

雪花模式是一種星型模式,其中維度表引用其他表。暴風雪模式是雪花模式的組合。

5.6.2 轉換的目的

在事實表和維度表的聯接中,星型轉換可以避免對事實表的完全掃描。

星形轉換通過僅獲取連線到約束維度行的相關事實行來提高效能。在某些情況下,查詢對維度表的其他列具有限制性篩選器。過濾器的組合可以顯著減少資料庫從事實表處理的資料集。

5.6.3 轉換工作原理

星型轉換新增子查詢謂詞,稱為點陣圖半連線謂詞,對應於約束維度。

當事實連線列上存在索引時,優化器將執行轉換。通過驅動點陣圖和和或子查詢提供的鍵值操作,資料庫只需要從事實表中檢索相關行。如果維度表上的謂詞過濾掉了重要的資料,那麼轉換可能比事實表上的完整掃描更有效。

在資料庫從事實表檢索到相關行之後,資料庫可能需要使用原始謂詞將這些行連線回維度表。當滿足以下條件時,資料庫可以消除維度表的 連線 :

維度表上的所有謂詞都是半連線子查詢謂詞的一部分。

從子查詢中選擇的列是唯一的。

維度列不在選擇列表、 GROUP BY 子句等中。

5.6.4 星轉換控制

STAR_TRANSFORMATION_ENABLED 初始化引數控制星型轉換。

該引數接受以下值:

•true

優化器通過自動識別事實和約束維度表來執行星型轉換。優化器僅在轉換計劃的成本低於備選方案的情況下執行星型轉換。此外,每當物化提高效能時,優化器將自動嘗試臨時錶轉換( 請參閱 臨時錶轉換 : 場景 ”)

false ( 預設 )

優化器不執行星型轉換。

•TEMP_DISABLE

這個值與true 相同,只是優化器不會嘗試臨時錶轉換。

5.6.5 轉換: 場景

這個場景演示了星型查詢的星型轉換。

示例5-5   查詢

以下查詢是加州所有城市在1999 年第一季度和第二季度的網路銷售總額 :

SELECT  c.cust_city ,

       t.calendar_quarter_desc ,

        SUM ( s.amount_sold )  sales_amount

   FROM  sales s ,  times t ,  customers c ,  channels ch

  WHERE  s.time_id =  t.time_id

    AND  s.cust_id =  c.cust_id

    AND  s.channel_id =  ch.channel_id

    AND  c.cust_state_province =   'CA'

    AND  ch.channel_desc =   'Internet'

    AND  t.calendar_quarter_desc IN   ( '1999-01' ,   '1999-02' )

  GROUP   BY  c.cust_city ,  t.calendar_quarter_desc ;

輸入如下:

在本例中,sales 是事實表,其他表是維度表。 sales 表包含產品每次銷售的一行,因此可以想象它包含數十億條銷售記錄。然而,只有少數產品在指定的季度通過網際網路銷售給加州的客戶。

5-6 星形變換

此示例顯示了示例5-5 中查詢的星形轉換。轉換避免了對銷售的全表掃描。

SELECT  c.cust_city ,

       t.calendar_quarter_desc ,

        SUM ( s.amount_sold )  sales_amount

   FROM  sales s ,  times t ,  customers c

  WHERE  s.time_id =  t.time_id

    AND  s.cust_id =  c.cust_id

    AND  c.cust_state_province =   'CA'

    AND  t.calendar_quarter_desc IN   ( '1999-01' ,   '1999-02' )

    AND  s.time_id IN

        ( SELECT  time_id

           FROM  times

          WHERE  calendar_quarter_desc IN   ( '1999-01' ,   '1999-02' ))

    AND  s.cust_id IN

        ( SELECT  cust_id FROM  customers WHERE  cust_state_province =   'CA' )

    AND  s.channel_id IN

        ( SELECT  channel_id FROM  channels WHERE  channel_desc =   'Internet' )

  GROUP   BY  c.cust_city ,  t.calendar_quarter_desc ;

5-7 星型 轉換 部分執行計劃

此示例顯示示例5-6 中星形轉換的執行計劃的編輯版本。

26 行顯示 sales 表有一個索引訪問路徑,而不是一個完整的表掃描。對於 channels (第 14 行)、 times (第 19 行)和 customers (第 24 行)的子查詢產生的每個鍵值,資料庫從 sales fact 表(第 15 20 25 行)的索引中檢索點陣圖。

點陣圖中的每個位對應於事實表中的一行。當子查詢中的鍵值與事實錶行中的值相同時,將設定該位。例如,在點陣圖101000 ... (省略號表示其餘行的值為0 )、事實表的第 1 行和第 3 行具有子查詢中的匹配鍵值。

12 17 22 行中的操作迭代子查詢中的鍵並檢索相應的點陣圖。在示例 5-6 中, customers 子查詢查詢其州或省為 CA 的客戶的 id 。假設點陣圖 101000 ... 對應於customers 表子查詢中的 customer ID 鍵值 103515 。還假設 customers 子查詢使用點陣圖 010000… ,生成鍵值 103516 ,這意味著 sales 中只有第 2 行具有來自子查詢的匹配鍵值。

資料庫合併(使用OR 運算子)每個子查詢(第 11 16 21 行)的點陣圖。在我們的客戶示例中,資料庫生成一個點陣圖 111000 ... 對於合併兩個點陣圖後的客戶子查詢:

101000... # bitmap corresponding to key 103515

010000... # bitmap corresponding to key 103516

---------

111000... # result of OR operation

在第10 行中,資料庫將 AND 運算子應用於合併的點陣圖。假設資料庫執行完所有或操作後,通道的點陣圖為 100000 ... 如果資料庫對此點陣圖和來自客戶的點陣圖 子查詢執行 AND 操作,則結果如下:

100000... # channels bitmap after all OR operations performed

111000... # customers bitmap after all OR operations performed

---------  

100000... # bitmap result of AND operation for channels and customers

在第9 行中,資料庫生成最終點陣圖的相應 rowid 。資料庫使用rowids sales 事實表中檢索行(第 26 行)。在我們的示例中,資料庫只生成一個 rowid ,它對應於第一行,因此只獲取一行,而不是掃描整個 sales 表。

5.6.6 臨時錶轉換 : 場景

在前面的場景中,優化器不會將表通道連線回sales 表,因為它沒有在外部引用,而 channel_id 是惟一的。

但是,如果優化器無法消除回聯接,則資料庫將子查詢結果儲存在臨時表中,以避免重新掃描維度表以生成點陣圖鍵並回聯接。此外,如果查詢是並行執行的,那麼資料庫將物化結果,以便每個並行執行伺服器可以從臨時表中選擇結果,而不是再次執行子查詢。

5-8 星轉換使用臨時表

在本例中,資料庫將客戶的子查詢結果物化為一個臨時表:

SELECT  t1.c1 cust_city ,

       t.calendar_quarter_desc calendar_quarter_desc ,

        SUM ( s.amount_sold )  sales_amount

   FROM  sales s ,  sh.times t ,  sys_temp_0fd9d6621_e7e24 t1

  WHERE  s.time_id =  t.time_id

    AND  s.cust_id =  t1.c0

    AND   ( t.calendar_quarter_desc =   '1999-q1'   OR

       t.calendar_quarter_desc =   '1999- q2' )

    AND  s.cust_id IN   ( SELECT  t1.c0 FROM  sys_temp_0fd9d6621_e7e24 t1 )

    AND  s.channel_id IN

        ( SELECT  ch.channel_id

           FROM  channels ch

          WHERE  ch.channel_desc =   'internet' )

    AND  s.time_id IN

        ( SELECT  t.time_id

           FROM  times t

          WHERE  t.calendar_quarter_desc =   '1999-q1'

             OR  t.calendar_quarter_desc =   '1999-q2' )

  GROUP   BY  t1.c1 ,  t.calendar_quarter_desc

優化器使用臨時表sys_temp_0fd9d6621_e7e24 替換客戶,並使用臨時表的相應列替換對列 cust_id cust_city 的引用。資料庫建立了包含兩列的臨時表 :(c0 NUMBER, c1 VARCHAR2(30)) 。這些列對應於客戶表的 cust_id cust_city 。資料庫通過在執行前一個查詢的開始執行以下查詢來填充臨時表 :

SELECT  c.cust_id ,  c.cust_city FROM  customers WHERE  c.cust_state_province =   'CA'

示例5-9 使用臨時表進行星型轉換的部分執行計劃

下面的示例顯示了示例5-8 中查詢的執行計劃的編輯版本 :

計劃的第1 2 3 行將客戶子查詢物化到臨時表中。在第 6 行,資料庫掃描臨時表 ( 而不是子查詢 ) ,從事實表構建點陣圖。第 27 行掃描臨時表,而不是掃描客戶。資料庫不需要對臨時表上的客戶應用篩選器,因為篩選器是在具體化臨時表時應用的。

5.7   In-Memory ( 向量組 BY)

記憶體聚合的關鍵優化是在掃描時進行聚合。

為了優化包含從單個大表到多個小表的聚合和連線的查詢塊,例如在典型的星型查詢中,轉換使用鍵向量和向量組操作。這些操作使用高效的記憶體內陣列進行連線和聚合,特別是當底層表是記憶體內的列表時,這些操作尤其有效。

5.8 指標持續時間臨時表

為了實現查詢的中間結果,Oracle 資料庫可以在查詢編譯期間隱式地在記憶體中建立一個指標持續時間的臨時表。

5.8.1 指標持續時間臨時表的用途

複雜查詢有時會多次處理相同的查詢塊,這會造成不必要的效能開銷。

為了避免這種情況,Oracle 資料庫可以為查詢結果自動建立臨時表,並在遊標期間將它們儲存在記憶體中。對於複雜的操作,例如 WITH 子句查詢、星型轉換和分組集,這種優化增強了重複使用的子查詢的中間結果的物化。通過這種方式,指標持續時間的臨時表可以提高效能並優化 I/O

5.8.2 指標持續時間臨時表的工作方式

指標定義臨時表的定義駐留在記憶體中。表定義與遊標相關聯,並且僅對執行遊標的會話可見。

使用指標持續時間臨時表時,資料庫執行以下步驟:

1. 選擇使用指標持續時間臨時表的計劃

2. 使用唯一名稱建立臨時表

3. 重寫查詢以引用臨時表

4. 將資料載入到記憶體中,直到沒有記憶體剩餘,在這種情況下,它在磁碟上建立臨時段

5. 執行查詢,從臨時表返回資料

6. 截斷表,釋放記憶體和磁碟上的任何臨時段

注意:

指標持續時間臨時表的後設資料只要指標在記憶體中,就會一直保留在記憶體中。後設資料沒有儲存在資料字典中,這意味著它在資料字典檢視中是不可見的。您不能顯式刪除後設資料。

前面的場景取決於記憶體的可用性。對於序列查詢,臨時表使用PGA 記憶體。

指標持續時間臨時表的實現類似於 排序 。如果沒有更多的記憶體可用,則資料庫將資料寫入臨時段。對於指標持續時間的臨時表,區別如下:

資料庫在查詢結束時釋放記憶體和臨時段,而不是在行源不再活動時釋放。

記憶體中的資料停留在記憶體中,不像排序中資料可以在記憶體和臨時段之間移動。

當資料庫使用游標持續時間臨時表時,關鍵字游標持續時間記憶體將出現在執行計劃中。

5.8.3 持續時間臨時表:示例

重複相同子查詢的WITH 查詢有時可以受益於遊標持續時間臨時表。

以下查詢使用WITH 子句建立三個子查詢塊:

WITH  q1 AS

  ( SELECT  department_id ,   SUM ( salary )  sum_sal

     FROM  hr.employees

    GROUP   BY  department_id ),

q2 AS

  ( SELECT   *   FROM  q1 ),

q3 AS

  ( SELECT  department_id ,  sum_sal FROM  q1 )

SELECT   *

   FROM  q1

UNION   ALL

SELECT   *

   FROM  q2

UNION   ALL

SELECT   *   FROM  q3 ;

下面的示例計劃顯示了轉換:

SELECT   *   FROM   TABLE ( DBMS_XPLAN.DISPLAY_CURSOR ( FORMAT => 'BASIC +ROWS +COST' ));  

在前面的計劃中,步驟1 中的臨時錶轉換指示資料庫使用遊標持續時間臨時表來執行查詢。步驟 2 中的 CURSOR DURATION MEMORY 關鍵字表示資料庫使用記憶體(如果可用)儲存 sys TEMP_0FD9D6606_1AE004 的結果。如果記憶體不可用,則資料庫將臨時資料寫入磁碟。

5.9 表擴充套件 (Table Expansion)

在表擴充套件中,優化器生成一個計劃,該計劃在分割槽表的主要讀取部分使用索引,但在表的活動部分不使用索引。

5.9.1 表格擴充套件的目的

基於索引的計劃可以提高效能,但索引維護會產生開銷。在許多資料庫中,DML 隻影響一小部分資料。

表擴充套件對高更新表使用基於索引的計劃。您可以只對主要讀取的資料建立索引,從而消除活動資料的索引開銷。這樣,表擴充套件在避免索引維護的同時提高了效能。

5.9.2 表擴充套件的工作原理

表分割槽使表擴充套件成為可能。

如果分割槽表上存在本地索引,優化器可以將該索引標記為對特定分割槽不可用。實際上,有些分割槽沒有索引。

在表擴充套件中,優化器將查詢轉換為UNION ALL 語句,其中一些子查詢訪問索引分割槽,其他子查詢訪問未索引分割槽。優化器可以為一個分割槽選擇最有效的訪問方法,而不管它是否存在於查詢中訪問的所有分割槽中。

優化器並不總是選擇表擴充套件:

表擴充套件是基於成本的。

雖然資料庫只跨UNION all 的所有分支訪問擴充套件表的每個分割槽一次,但資料庫連線到它的任何表都在每個分支中訪問。

語義問題可能導致擴充套件無效。

例如,出現在外部聯接右側的表對於表擴充套件無效。

您可以使用EXPAND_table 提示來控制表擴充套件。提示覆蓋基於成本的決策,但不覆蓋語義檢查。

5.9.3   表擴充套件 : 場景

優化器根據查詢中出現的謂詞跟蹤必須從每個表訪問哪些分割槽。分割槽修剪使優化器能夠使用表擴充套件來生成更優的計劃。

假設

該場景假設如下:

您希望對 sh.sales 表執行星型查詢,該表在 time_id 列上進行了範圍分割槽。

您希望禁用特定分割槽上的索引,以檢視錶擴充套件的好處。

使用 表擴充套件 :

1. sh 使用者身份登入資料庫。

2. 執行以下查詢 :

SELECT   *

   FROM  sales

  WHERE  time_id >=  TO_DATE ( '2000-01-01 00:00:00' ,   'SYYYY-MM-DD HH24:MI:SS' )

    AND  prod_id =   38 ;

使用DBMS_XPLAN 檢視執行計劃

SET LINESIZE 150

SET  PAGESIZE 0

SELECT   *   FROM   TABLE ( DBMS_XPLAN.DISPLAY_CURSOR ( format =>   'BASIC,PARTITION' ));

如下面的Pstart Pstop 列所示,優化器從過濾器中確定表中的 28 個分割槽中只有 16 個必須被訪問 :

在優化器確定要訪問的分割槽之後,它將考慮所有這些分割槽上可用的任何索引。在前面的計劃中,優化器選擇使用sales_prod_bix 點陣圖索引。

4. 禁用 sales 表的 SALES_1995 分割槽上的索引 :

ALTER   INDEX  sales_prod_bix MODIFY   PARTITION  sales_1995 UNUSABLE ;

前面的DDL 禁用分割槽 1 上的索引,該分割槽包含 1996 年以前的所有銷售。

5. 再次執行 sales 查詢,然後查詢 DBMS_XPLAN 以獲得計劃。輸出顯示計劃沒有改變 :

計劃是相同的,因為禁用的索引分割槽與查詢無關。如果查詢訪問的所有分割槽都建立了索引,那麼資料庫可以使用索引回答查詢。因為查詢只訪問分割槽16 28 ,所以禁用分割槽 1 上的索引不會影響計劃。

6. 禁用分割槽 28 的索引 (SALES_Q4_2003) ,該分割槽是查詢需要訪問的分割槽 :

ALTER   INDEX  sales_prod_bix MODIFY   PARTITION  sales_1995 UNUSABLE ;

ALTER   INDEX  sales_prod_bix MODIFY   PARTITION  sales_q4_2003 UNUSABLE ;  

ALTER   INDEX  sales_time_bix MODIFY   PARTITION  sales_q4_2003 UNUSABLE ;

通過禁用查詢確實需要訪問的分割槽上的索引,查詢就不能再使用這個索引( 沒有表展開 )

7. 使用 DBMS_XPLAN 查詢計劃。

如下圖所示,優化器不使用索引:

在前面的示例中,查詢訪問16 個分割槽。在其中 15 個分割槽上,有一個索引可用,但是最後一個分割槽沒有可用的索引。

因為優化器必須選擇一個或另一個訪問路徑,所以優化器不能在任何分割槽上使用索引。

8. 通過表擴充套件,優化器按如下方式重寫原始查詢 :

SELECT   *

   FROM  sales

  WHERE  time_id >=  TO_DATE ( '2000-01-01 00:00:00' ,   'SYYYY-MM-DD HH24:MI:SS' )

    AND  time_id <  TO_DATE ( '2003-10-01 00:00:00' ,   'SYYYY-MM-DD HH24:MI:SS' )

    AND  prod_id =   38

UNION   ALL

SELECT   *

   FROM  sales

  WHERE  time_id >=  TO_DATE ( '2003-10-01 00:00:00' ,   'SYYYY-MM-DD HH24:MI:SS' )

    AND  time_id <  TO_DATE ( '2004-01-01 00:00:00' ,   'SYYYY-MM-DD HH24:MI:SS' )

    AND  prod_id =   38 ;

在前面的查詢中,UNION 中的第一個查詢塊將訪問所有已建立索引的分割槽,而第二個查詢塊將訪問未建立索引的分割槽。這兩個子查詢使優化器能夠選擇在第一個查詢塊中使用索引,如果它比使用所有被訪問分割槽的表掃描更優的話。

9. 使用 DBMS_XPLAN 查詢計劃。計劃內容如下 :

如前面的計劃所示, 查詢優化器使用 UNION ALL 兩塊 ( 步驟 2) 。優化器選擇索引訪問分割槽 13 27 日在第一個查詢塊 ( 步驟 6) 。因為沒有可用索引分割槽 28 日優化器選擇一個全表掃描在第二個查詢塊 ( 步驟 8)

5.9.4 表展開與星 型轉換 : 場景

星型轉換支援特定型別的查詢,以避免訪問大型事實表的大部分。

星型轉換需要定義幾個索引,在主動更新的表中可能會有開銷。通過表擴充套件,您可以只在不活動的分割槽上定義索引,這樣優化器就可以只在表的索引部分上考慮星型轉換。

假設

該場景假設如下:

查詢 星型轉換 : 場景 中使用的相同模式。

•sales 的最後一個分割槽正在被積極地更新,時間分割槽表通常都是這樣。

您希望優化器利用表擴充套件。

要在星型查詢中利用表擴充套件:

1. 按如下方式禁用最後一個分割槽上的索引 :

ALTER   INDEX  sales_channel_bix MODIFY   PARTITION  sales_q4_2003 UNUSABLE ;  

ALTER   INDEX  sales_cust_bix MODIFY   PARTITION  sales_q4_2003 UNUSABLE ;

2. 執行以下星號查詢 :

SELECT  t.calendar_quarter_desc ,   SUM ( s.amount_sold )  sales_amount

   FROM  sales s ,  times t ,  customers c ,  channels ch

  WHERE  s.time_id =  t.time_id

    AND  s.cust_id =  c.cust_id

    AND  s.channel_id =  ch.channel_id

    AND  c.cust_state_province =   'CA'

    AND  ch.channel_desc =   'Internet'

    AND  t.calendar_quarter_desc IN   ( '1999-01' ,   '1999-02' )

  GROUP   BY  t.calendar_quarter_desc ;

3. 執行計劃如下:

前面的計劃使用表擴充套件。訪問除最後一個分割槽以外的每個分割槽的UNION ALL 分支使用星型轉換。因為分割槽 28 上的索引被禁用,所以資料庫使用全表掃描訪問最終分割槽。

5.10 連線因式分解 (Join Factorization)

在基於成本的轉換( 稱為連線分解 ) 中,優化器可以分解 UNION ALL 查詢分支的公共計算。

5.10.1 連線因子分解的目的

UNION ALL 查詢在資料庫應用程式中很常見,尤其是在資料整合應用程式中。

通常,UNION ALL 查詢中的分支引用相同的基表。沒有連線因子分解,優化器獨立地評估 UNION ALL 查詢的每個分支,這會導致重複的處理,包括資料訪問和連線。連線分解轉換可以在聯合的所有分支之間共享公共計算。避免對大型基表進行額外的掃描可以極大地提高效能。

5.10.2 連線因式分解的工作原理

連線分解可以分解多個表,並且可以從兩個以上的UNION ALL 分支中分解。

通過示例可以很好地解釋連線因式分解。

示例5-10 union ALL 查詢

下面的查詢顯示了四個表(t1 t2 t3 t4) 和兩個 UNION ALL 分支的查詢 :

SELECT  t1.c1 ,  t2.c2

   FROM  t1 ,  t2 ,  t3

  WHERE  t1.c1 =  t2.c1

    AND  t1.c1 >   1

    AND  t2.c2 =   2

    AND  t2.c2 =  t3.c2

UNION   ALL

SELECT  t1.c1 ,  t2.c2

   FROM  t1 ,  t2 ,  t4

  WHERE  t1.c1 =  t2.c1

    AND  t1.c1 >   1

    AND  t2.c3 =  t4.c3

在前面的查詢中,表t1 同時出現在 UNION ALL 分支中,與過濾謂詞 t1 一樣。 c1 > 1 和連線謂詞 t1 . c1 = t2 . c1 。在不進行任何轉換的情況下,資料庫必須對錶 t1 執行兩次掃描和過濾,每個分支執行一次。

5-11 分解查詢

5 - 10

SELECT  t1.c1 ,  VW_JF_1.item_2

   FROM  t1 ,

        ( SELECT  t2.c1 item_1 ,  t2.c2 item_2

           FROM  t2 ,  t3

          WHERE  t2.c2 =  t3.c2

            AND  t2.c2 =   2

         UNION   ALL

         SELECT  t2.c1 item_1 ,  t2.c2 item_2 FROM  t2 ,  t4 WHERE  t2.c3 =  t4.c3 )  VW_JF_1

  WHERE  t1.c1 =  VW_JF_1.item_1

    AND  t1.c1 >   1

在本例中,由於對錶t1 進行了因式分解,因此資料庫僅對 t1 執行一次表掃描和過濾。如果 t1 很大,那麼這種因式分解避免了兩次掃描和過濾 t1 的巨大效能代價。

注意:

如果UNION 中的所有分支都有使用 DISTINCT 的子句函式,則聯接因式分解無效。

5.10.3 分解和連線順序 : 場景

連線因數分解可以為連線順序創造更多的可能性

5-12 查詢涉及 5 個表

在下面的查詢中,view V 與例 5-10 中的查詢相同 :

SELECT   *

   FROM  t5 ,

        ( SELECT  t1.c1 ,  t2.c2

           FROM  t1 ,  t2 ,  t3

          WHERE  t1.c1 =  t2.c1

            AND  t1.c1 >   1

            AND  t2.c2 =   2

            AND  t2.c2 =  t3.c2

         UNION   ALL

         SELECT  t1.c1 ,  t2.c2

           FROM  t1 ,  t2 ,  t4

          WHERE  t1.c1 =  t2.c1

            AND  t1.c1 >   1

            AND  t2.c3 =  t4.c3 )  V

  WHERE  t5.c1 =  V.c1

 

t1t2t3t5

5-13 t1 V 中因式分解

如果join factorization t1 view V 中進行因式分解,如下面的查詢所示,則資料庫可以將 t1 t5 進行連線 :

SELECT   *

   FROM  t5 ,

        ( SELECT  t1.c1 ,  VW_JF_1.item_2

           FROM  t1 ,

                ( SELECT  t2.c1 item_1 ,  t2.c2 item_2

                   FROM  t2 ,  t3

                  WHERE  t2.c2 =  t3.c2

                    AND  t2.c2 =   2

                 UNION   ALL

                 SELECT  t2.c1 item_1 ,  t2.c2 item_2

                   FROM  t2 ,  t4

                  WHERE  t2.c3 =  t4.c3 )  VW_JF_1

          WHERE  t1.c1 =  VW_JF_1.item_1

            AND  t1.c1 >   1 )

  WHERE  t5.c1 =  V.c1

前面的查詢轉換開啟了新的連線順序。然而,連線因數分解強制使用特定的連線順序。例如,在前面的查詢中,表t2 t3 出現在檢視 VW_JF_1 中的 UNION ALL 查詢的第一個分支中。資料庫必須先連線 t2 t3 ,然後才能連線 t1 ,這在 VW_JF_1 檢視中沒有定義。強制的連線順序不一定是最佳的連線順序。由於這個原因,優化器使用基於成本的轉換框架執行連線分解。優化器計算包含和不包含連線因子分解的計劃的成本,然後選擇最便宜的計劃。

5-14 從檢視 V 中分解 t1 ,去掉了檢視定義

下面的查詢與例5-13 中的查詢相同,但是去掉了檢視定義,這樣分解就更容易看到了 :

SELECT   *

   FROM  t5 ,

        ( SELECT  t1.c1 ,  VW_JF_1.item_2

           FROM  t1 ,  VW_JF_1

          WHERE  t1.c1 =  VW_JF_1.item_1

            AND  t1.c1 >   1 )

  WHERE  t5.c1 =  V.c1

5.10.4 外部連線的因式分解 : 場景

該資料庫支援外部連線、反連線和半連線的連線因數分解,但僅針對此類連線中的正確表。

例如,join factorization 可以通過對 t2 進行因子分解來轉換下面的 UNION ALL 查詢 :

SELECT  t1.c2 ,  t2.c2

   FROM  t1 ,  t2

  WHERE  t1.c1 =  t2.c1 (+)

    AND  t1.c1 =   1

UNION   ALL

SELECT  t1.c2 ,  t2.c2

   FROM  t1 ,  t2

  WHERE  t1.c1 =  t2.c1 (+)

    AND  t1.c1 =   2

下面的示例顯示了轉換。表t2 現在不再出現在聯合子查詢的所有分支中。

SELECT  VW_JF_1.item_2 ,  t2.c2

   FROM  t2 ,

        ( SELECT  t1.c1 item_1 ,  t1.c2 item_2

           FROM  t1

          WHERE  t1.c1 =   1

         UNION   ALL

         SELECT  t1.c1 item_1 ,  t1.c2 item_2 FROM  t1 WHERE  t1.c1 =   2 )  VW_JF_1

  WHERE  VW_JF_1.item_1 =  t2.c1 (+)

歡迎關注我的微信公眾號"IT小Chen",共同學習,共同成長!!!

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29785807/viewspace-2680118/,如需轉載,請註明出處,否則將追究法律責任。

相關文章