檢視合併(View Merging)

leixue0906發表於2015-05-27

在使用檢視或巢狀檢視的查詢語句中,oracle 為了取得最優的執行計劃會將這些檢視進行合併,將檢視中的表與外部查詢的表進行連線。

  1. --示例:  
  2. SQL> select e.first_name, e.last_name, dept_locs_v.street_address, dept_locs_v.postal_code  
  3.   2  from employees e,  
  4.   3       (select d.department_id, d.department_name, l.street_address, l.postal_code  
  5.   4        from departments d, locations l  
  6.   5        where d.location_id = l.location_id) dept_locs_v  
  7.   6  where dept_locs_v.department_id = e.department_id  
  8.   7  and e.last_name = 'Smith';  
  9.   
  10. 執行計劃  
  11. ----------------------------------------------------------  
  12. Plan hash value: 994428606  
  13.   
  14. ---------------------------------------------------------------------------------------------  
  15. | Id  | Operation                     | Name        | Rows  | Bytes | Cost (%CPU)| Time     |  
  16. ---------------------------------------------------------------------------------------------  
  17. |   0 | SELECT STATEMENT              |             |     1 |    56 |     4   (0)| 00:00:01 |  
  18. |   1 |  NESTED LOOPS                 |             |     1 |    56 |     4   (0)| 00:00:01 |  
  19. |   2 |   NESTED LOOPS                |             |     1 |    25 |     3   (0)| 00:00:01 |  
  20. |   3 |    TABLE ACCESS BY INDEX ROWID| EMPLOYEES   |     1 |    18 |     2   (0)| 00:00:01 |  
  21. |*  4 |     INDEX RANGE SCAN          | EMP_NAME_IX |     1 |       |     1   (0)| 00:00:01 |  
  22. |   5 |    TABLE ACCESS BY INDEX ROWID| DEPARTMENTS |     1 |     7 |     1   (0)| 00:00:01 |  
  23. |*  6 |     INDEX UNIQUE SCAN         | DEPT_ID_PK  |     1 |       |     0   (0)| 00:00:01 |  
  24. |   7 |   TABLE ACCESS BY INDEX ROWID | LOCATIONS   |     1 |    31 |     1   (0)| 00:00:01 |  
  25. |*  8 |    INDEX UNIQUE SCAN          | LOC_ID_PK   |     1 |       |     0   (0)| 00:00:01 |  
  26. ---------------------------------------------------------------------------------------------  
  27.   
  28. Predicate Information (identified by operation id):  
  29. ---------------------------------------------------  
  30.   
  31.    4 - access("E"."LAST_NAME"='Smith')  
  32.    6 - access("E"."DEPARTMENT_ID"="D"."DEPARTMENT_ID")  
  33.    8 - access("D"."LOCATION_ID"="L"."LOCATION_ID")  
  34.   
  35. --使用no_merge禁止檢視合併  
  36. SQL> select /*+ no_merge(dept_locs_v)*/e.first_name, e.last_name, dept_locs_v.street_address, dept_locs_v.postal_code  
  37.   2  from employees e,  
  38.   3       (select d.department_id, d.department_name, l.street_address, l.postal_code  
  39.   4        from departments d, locations l  
  40.   5        where d.location_id = l.location_id) dept_locs_v  
  41.   6  where dept_locs_v.department_id = e.department_id  
  42.   7  and e.last_name = 'Smith';  
  43.   
  44. 執行計劃  
  45. ----------------------------------------------------------  
  46. Plan hash value: 842533999  
  47.   
  48. --------------------------------------------------------------------------------------------------  
  49. | Id  | Operation                     | Name             | Rows  | Bytes | Cost (%CPU)| Time     |  
  50. --------------------------------------------------------------------------------------------------  
  51. |   0 | SELECT STATEMENT              |                  |     1 |    61 |     7  (15)| 00:00:01 |  
  52. |*  1 |  HASH JOIN                    |                  |     1 |    61 |     7  (15)| 00:00:01 |  
  53. |   2 |   TABLE ACCESS BY INDEX ROWID | EMPLOYEES        |     1 |    18 |     2   (0)| 00:00:01 |  
  54. |*  3 |    INDEX RANGE SCAN           | EMP_NAME_IX      |     1 |       |     1   (0)| 00:00:01 |  
  55. |   4 |   VIEW                        |                  |    27 |  1161 |     4   (0)| 00:00:01 |  
  56. |   5 |    TABLE ACCESS BY INDEX ROWID| DEPARTMENTS      |     1 |     7 |     1   (0)| 00:00:01 |  
  57. |   6 |     NESTED LOOPS              |                  |    27 |  1026 |     4   (0)| 00:00:01 |  
  58. |   7 |      TABLE ACCESS FULL        | LOCATIONS        |    23 |   713 |     3   (0)| 00:00:01 |  
  59. |*  8 |      INDEX RANGE SCAN         | DEPT_LOCATION_IX |     4 |       |     0   (0)| 00:00:01 |  
  60. --------------------------------------------------------------------------------------------------  
  61.   
  62. Predicate Information (identified by operation id):  
  63. ---------------------------------------------------  
  64.   
  65.    1 - access("DEPT_LOCS_V"."DEPARTMENT_ID"="E"."DEPARTMENT_ID")  
  66.    3 - access("E"."LAST_NAME"='Smith')  
  67.    8 - access("D"."LOCATION_ID"="L"."LOCATION_ID")  

可以使用hint來引導最佳化器,MERGE(v),合併檢視。NO_MERGE(v),如果在使用該檢視的父查詢中使用該提示,禁止該檢視被合併。
並不是任何使用檢視的查詢語句都會進行檢視合併,在檢視中出現以下操作時不能進行檢視合併:
    Set operators(union,union all,intersact,minus)
    Aggregation(avg,count,max,min,sum)
    Rownum
    Connect by
    Group by(隱藏引數_complex_view_merging為true時,可能合併)
    Distinct(隱藏引數_complex_view_merging為true時,可能合併)

  1. SQL> --使用rownum, 沒有合併  
  2. SQL> select e.first_name, e.last_name, dept_locs_v.street_address, dept_locs_v.postal_code  
  3.   2  from employees e,  
  4.   3       (select  rownum ,d.department_id, d.department_name, l.street_address, l.postal_code  
  5.   4        from departments d, locations l  
  6.   5        where d.location_id = l.location_id order by 2) dept_locs_v  
  7.   6  where dept_locs_v.department_id = e.department_id  
  8.   7  and e.last_name = 'Smith';  
  9.   
  10. 執行計劃  
  11. ----------------------------------------------------------  
  12. Plan hash value: 2276247677  
  13.   
  14. -----------------------------------------------------------------------------------------------  
  15. | Id  | Operation                       | Name        | Rows  | Bytes | Cost (%CPU)| Time     |  
  16. -----------------------------------------------------------------------------------------------  
  17. |   0 | SELECT STATEMENT                |             |     1 |    52 |     6  (17)| 00:00:01 |  
  18. |*  1 |  HASH JOIN                      |             |     1 |    52 |     6  (17)| 00:00:01 |  
  19. |   2 |   TABLE ACCESS BY INDEX ROWID   | EMPLOYEES   |     1 |    18 |     2   (0)| 00:00:01 |  
  20. |*  3 |    INDEX RANGE SCAN             | EMP_NAME_IX |     1 |       |     1   (0)| 00:00:01 |  
  21. |   4 |   VIEW                          |             |    27 |   918 |     3   (0)| 00:00:01 |  
  22. |   5 |    COUNT                        |             |       |       |            |          |  
  23. |   6 |     NESTED LOOPS                |             |    27 |  1350 |     3   (0)| 00:00:01 |  
  24. |   7 |      TABLE ACCESS BY INDEX ROWID| DEPARTMENTS |    27 |   513 |     2   (0)| 00:00:01 |  
  25. |   8 |       INDEX FULL SCAN           | DEPT_ID_PK  |    27 |       |     1   (0)| 00:00:01 |  
  26. |   9 |      TABLE ACCESS BY INDEX ROWID| LOCATIONS   |     1 |    31 |     1   (0)| 00:00:01 |  
  27. |* 10 |       INDEX UNIQUE SCAN         | LOC_ID_PK   |     1 |       |     0   (0)| 00:00:01 |  
  28. -----------------------------------------------------------------------------------------------  
  29.   
  30. Predicate Information (identified by operation id):  
  31. ---------------------------------------------------  
  32.   
  33.    1 - access("DEPT_LOCS_V"."DEPARTMENT_ID"="E"."DEPARTMENT_ID")  
  34.    3 - access("E"."LAST_NAME"='Smith')  
  35.   10 - access("D"."LOCATION_ID"="L"."LOCATION_ID")  

還有,當檢視在外連線的右側時,有些不能合併,有些能合併。
當檢視在外連線的左側,並且該檢視與外部查詢的同一表進行多於一次的外連線時,不能合併。這源於外連線的限制,外部查詢的每一個表最多隻能與檢視中的表進行一次連線。

  1. --當檢視在外連線的右側時,不能合併。  
  2. SQL> select e1.first_name||' '||e1.last_name emp_name, dept_managers_v.manager_name,  
  3.   2        dept_managers_v.department_name  
  4.   3  from employees e1,  
  5.   4      (select e2.manager_id, e2.first_name||' '||e2.last_name as manager_name,  
  6.   5              d.department_id, d.department_name  
  7.   6       from departments d, employees e2  
  8.   7       where d.manager_id = e2.employee_id) dept_managers_v  
  9.   8  where dept_managers_v.department_id(+) = e1.department_id;  
  10.   
  11. 執行計劃  
  12. ----------------------------------------------------------  
  13. Plan hash value: 3319085545  
  14.   
  15. ------------------------------------------------------------------------------------------------  
  16. | Id  | Operation                      | Name          | Rows  | Bytes | Cost (%CPU)| Time     |  
  17. ------------------------------------------------------------------------------------------------  
  18. |   0 | SELECT STATEMENT               |               |   107 |  7811 |     9  (12)| 00:00:01 |  
  19. |*  1 |  HASH JOIN OUTER               |               |   107 |  7811 |     9  (12)| 00:00:01 |  
  20. |   2 |   TABLE ACCESS FULL            | EMPLOYEES     |   107 |  1926 |     3   (0)| 00:00:01 |  
  21. |   3 |   VIEW                         |               |    11 |   605 |     5   (0)| 00:00:01 |  
  22. |   4 |    NESTED LOOPS                |               |    11 |   418 |     5   (0)| 00:00:01 |  
  23. |*  5 |     TABLE ACCESS FULL          | DEPARTMENTS   |    11 |   209 |     3   (0)| 00:00:01 |  
  24. |   6 |     TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     1 |    19 |     1   (0)| 00:00:01 |  
  25. |*  7 |      INDEX UNIQUE SCAN         | EMP_EMP_ID_PK |     1 |       |     0   (0)| 00:00:01 |  
  26. ------------------------------------------------------------------------------------------------  
  27.   
  28. Predicate Information (identified by operation id):  
  29. ---------------------------------------------------  
  30.   
  31.    1 - access("DEPT_MANAGERS_V"."DEPARTMENT_ID"(+)="E1"."DEPARTMENT_ID")  
  32.    5 - filter("D"."MANAGER_ID" IS NOT NULL)  
  33.    7 - access("D"."MANAGER_ID"="E2"."EMPLOYEE_ID")  
  34.   
  35. --當檢視在外連線的左側,並且該檢視與外部查詢的同一表進行一次外連線時,能夠合併。  
  36. SQL> select e1.first_name||' '||e1.last_name emp_name, dept_managers_v.manager_name,  
  37.   2        dept_managers_v.department_name  
  38.   3  from employees e1,  
  39.   4      (select e2.manager_id, e2.first_name||' '||e2.last_name as manager_name,  
  40.   5              d.department_id, d.department_name  
  41.   6       from departments d, employees e2  
  42.   7       where d.manager_id = e2.employee_id) dept_managers_v  
  43.   8  where dept_managers_v.department_id = e1.department_id(+);  
  44.   
  45. 執行計劃  
  46. ----------------------------------------------------------  
  47. Plan hash value: 508024882  
  48.   
  49. -----------------------------------------------------------------------------------------------  
  50. | Id  | Operation                     | Name          | Rows  | Bytes | Cost (%CPU)| Time     |  
  51. -----------------------------------------------------------------------------------------------  
  52. |   0 | SELECT STATEMENT              |               |   106 |  5936 |     8  (13)| 00:00:01 |  
  53. |   1 |  NESTED LOOPS                 |               |   106 |  5936 |     8  (13)| 00:00:01 |  
  54. |   2 |   MERGE JOIN OUTER            |               |   106 |  3922 |     6  (17)| 00:00:01 |  
  55. |*  3 |    TABLE ACCESS BY INDEX ROWID| DEPARTMENTS   |    11 |   209 |     2   (0)| 00:00:01 |  
  56. |   4 |     INDEX FULL SCAN           | DEPT_ID_PK    |    27 |       |     1   (0)| 00:00:01 |  
  57. |*  5 |    SORT JOIN                  |               |   107 |  1926 |     4  (25)| 00:00:01 |  
  58. |   6 |     TABLE ACCESS FULL         | EMPLOYEES     |   107 |  1926 |     3   (0)| 00:00:01 |  
  59. |   7 |   TABLE ACCESS BY INDEX ROWID | EMPLOYEES     |     1 |    19 |     1   (0)| 00:00:01 |  
  60. |*  8 |    INDEX UNIQUE SCAN          | EMP_EMP_ID_PK |     1 |       |     0   (0)| 00:00:01 |  
  61. -----------------------------------------------------------------------------------------------  
  62.   
  63. Predicate Information (identified by operation id):  
  64. ---------------------------------------------------  
  65.   
  66.    3 - filter("D"."MANAGER_ID" IS NOT NULL)  
  67.    5 - access("D"."DEPARTMENT_ID"="E1"."DEPARTMENT_ID"(+))  
  68.        filter("D"."DEPARTMENT_ID"="E1"."DEPARTMENT_ID"(+))  
  69.    8 - access("D"."MANAGER_ID"="E2"."EMPLOYEE_ID")    
  70.     
  71. --當檢視在外連線的左側,並且該檢視與外部查詢的同一表進行多於一次的外連線時,不能合併。  
  72. SQL> select e1.first_name||' '||e1.last_name emp_name, dept_managers_v.manager_name,  
  73.   2        dept_managers_v.department_name  
  74.   3  from employees e1,  
  75.   4      (select e2.manager_id, e2.first_name||' '||e2.last_name as manager_name,  
  76.   5              d.department_id, d.department_name  
  77.   6       from departments d, employees e2  
  78.   7       where d.manager_id = e2.employee_id) dept_managers_v  
  79.   8  where dept_managers_v.department_id = e1.department_id(+)  
  80.   9  and dept_managers_v.manager_id = e1.manager_id(+);  
  81.   
  82. 執行計劃  
  83. ----------------------------------------------------------  
  84. Plan hash value: 1655263574  
  85.   
  86. ------------------------------------------------------------------------------------------------  
  87. | Id  | Operation                      | Name          | Rows  | Bytes | Cost (%CPU)| Time     |  
  88. ------------------------------------------------------------------------------------------------  
  89. |   0 | SELECT STATEMENT               |               |    11 |   990 |     9  (12)| 00:00:01 |  
  90. |*  1 |  HASH JOIN OUTER               |               |    11 |   990 |     9  (12)| 00:00:01 |  
  91. |   2 |   VIEW                         |               |    11 |   748 |     5   (0)| 00:00:01 |  
  92. |   3 |    NESTED LOOPS                |               |    11 |   462 |     5   (0)| 00:00:01 |  
  93. |*  4 |     TABLE ACCESS FULL          | DEPARTMENTS   |    11 |   209 |     3   (0)| 00:00:01 |  
  94. |   5 |     TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     1 |    23 |     1   (0)| 00:00:01 |  
  95. |*  6 |      INDEX UNIQUE SCAN         | EMP_EMP_ID_PK |     1 |       |     0   (0)| 00:00:01 |  
  96. |   7 |   TABLE ACCESS FULL            | EMPLOYEES     |   107 |  2354 |     3   (0)| 00:00:01 |  
  97. ------------------------------------------------------------------------------------------------  
  98.   
  99. Predicate Information (identified by operation id):  
  100. ---------------------------------------------------  
  101.   
  102.    1 - access("DEPT_MANAGERS_V"."DEPARTMENT_ID"="E1"."DEPARTMENT_ID"(+) AND  
  103.               "DEPT_MANAGERS_V"."MANAGER_ID"="E1"."MANAGER_ID"(+))  
  104.    4 - filter("D"."MANAGER_ID" IS NOT NULL)  
  105.    6 - access("D"."MANAGER_ID"="E2"."EMPLOYEE_ID")  

 

複雜檢視或巢狀檢視(包含有group by 或 distinct)的檢視合併由_complex_view_merging隱藏引數控制,當為true時,最佳化器評估可能應用檢視合併,當為false時,即使使用merge hint也不能應用檢視合併。以group by 為例:
當_complex_view_merging設定為true時,以下sql語句
select d.loc,v.avg_sal
from dept d,( select deptno,avg(sal) avg_sal,min(sal) min_sal,max(sal) max_sal 
 from emp group by deptno) v
where d.deptno=v.deptno and d.loc='CHICAGO';

可能會由查詢轉換器經檢視合併將其轉換為以下sql執行
select d.loc,avg(e.sal) avg_sal
from dept d,emp e
where d.deptno=e.deptno and d.loc='CHICAGO'
group by d.rowid,d.loc;

  1. SQL> conn / as sysdba  
  2. 已連線。  
  3. SQL> @hidParam.sql  
  4. 輸入 parname 的值:  _complex_view_merging  
  5. 原值    3:  WHERE   x.indx = y.indx AND  ksppinm = '&parName'  
  6. 新值    3:  WHERE   x.indx = y.indx AND  ksppinm = '_complex_view_merging'  
  7.   
  8. KSPPINM         KSPPSTVL   KSPPDESC  
  9. --------------- ---------- --------------------------------------------------  
  10. _complex_view_m TRUE       enable complex view merging  
  11. erging  
  12.   
  13.   
  14. SQL> conn scott/tiger  
  15. 已連線。  
  16. SQL> select d.loc,v.avg_sal  
  17.   2  from dept d,( select deptno,avg(sal) avg_sal,min(sal) min_sal,max(sal) max_sal  
  18.   3   from emp group by deptno) v  
  19.   4  where d.deptno=v.deptno and d.loc='CHICAGO';  
  20.   
  21. 執行計劃  
  22. ----------------------------------------------------------  
  23. Plan hash value: 2941989041  
  24.   
  25. ----------------------------------------------------------------------------------------  
  26. | Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |  
  27. ----------------------------------------------------------------------------------------  
  28. |   0 | SELECT STATEMENT             |         |     1 |    37 |     7  (43)| 00:00:01 |  
  29. |   1 |  NESTED LOOPS                |         |     1 |    37 |     7  (43)| 00:00:01 |  
  30. |   2 |   VIEW                       |         |     3 |    78 |     6  (50)| 00:00:01 |  
  31. |   3 |    HASH GROUP BY             |         |     3 |    21 |     6  (50)| 00:00:01 |  
  32. |   4 |     TABLE ACCESS FULL        | EMP     | 10000 | 70000 |     4  (25)| 00:00:01 |  
  33. |*  5 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    11 |     1   (0)| 00:00:01 |  
  34. |*  6 |    INDEX UNIQUE SCAN         | PK_DEPT |     1 |       |     0   (0)| 00:00:01 |  
  35. ----------------------------------------------------------------------------------------  
  36.   
  37. Predicate Information (identified by operation id):  
  38. ---------------------------------------------------  
  39.   
  40.    5 - filter("D"."LOC"='CHICAGO')  
  41.    6 - access("D"."DEPTNO"="V"."DEPTNO")  
  42.   
  43. --手動改變統計資訊  
  44. SQL>  exec dbms_stats.set_table_stats(user,'EMP',numrows=>100000);  
  45.   
  46. PL/SQL 過程已成功完成。  
  47.   
  48. --至此,應用了檢視合併  
  49. SQL> select d.loc,v.avg_sal  
  50.   2  from dept d,( select deptno,avg(sal) avg_sal,min(sal) min_sal,max(sal) max_sal  
  51.   3   from emp group by deptno) v  
  52.   4  where d.deptno=v.deptno and d.loc='CHICAGO';  
  53.   
  54. 執行計劃  
  55. ----------------------------------------------------------  
  56. Plan hash value: 2006461124  
  57.   
  58. ----------------------------------------------------------------------------  
  59. | Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
  60. ----------------------------------------------------------------------------  
  61. |   0 | SELECT STATEMENT    |      |     3 |    81 |    18  (67)| 00:00:01 |  
  62. |   1 |  HASH GROUP BY      |      |     3 |    81 |    18  (67)| 00:00:01 |  
  63. |*  2 |   HASH JOIN         |      | 33333 |   878K|    13  (54)| 00:00:01 |  
  64. |*  3 |    TABLE ACCESS FULL| DEPT |     1 |    20 |     3   (0)| 00:00:01 |  
  65. |   4 |    TABLE ACCESS FULL| EMP  |   100K|   683K|     8  (63)| 00:00:01 |  
  66. ----------------------------------------------------------------------------  
  67.   
  68. Predicate Information (identified by operation id):  
  69. ---------------------------------------------------  
  70.   
  71.    2 - access("D"."DEPTNO"="DEPTNO")  
  72.    3 - filter("D"."LOC"='CHICAGO')  
  73.   
  74.      
  75. --將_complex_view_merging隱藏引數設定為false之後,即使使用merge引導最佳化器合併檢視也是枉然。  
  76. SQL> alter session set "_complex_view_merging"=false;  
  77.   
  78. 會話已更改。  
  79.   
  80. SQL> select d.loc,v.avg_sal  
  81.   2  from dept d,( select deptno,avg(sal) avg_sal,min(sal) min_sal,max(sal) max_sal  
  82.   3   from emp group by deptno) v  
  83.   4  where d.deptno=v.deptno and d.loc='CHICAGO';  
  84.   
  85. 執行計劃  
  86. ----------------------------------------------------------  
  87. Plan hash value: 2941989041  
  88.   
  89. ----------------------------------------------------------------------------------------  
  90. | Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |  
  91. ----------------------------------------------------------------------------------------  
  92. |   0 | SELECT STATEMENT             |         |     1 |    37 |    23  (83)| 00:00:01 |  
  93. |   1 |  NESTED LOOPS                |         |     1 |    37 |    23  (83)| 00:00:01 |  
  94. |   2 |   VIEW                       |         |     3 |    78 |    22  (87)| 00:00:01 |  
  95. |   3 |    HASH GROUP BY             |         |     3 |    21 |    22  (87)| 00:00:01 |  
  96. |   4 |     TABLE ACCESS FULL        | EMP     |   100K|   683K|     8  (63)| 00:00:01 |  
  97. |*  5 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    11 |     1   (0)| 00:00:01 |  
  98. |*  6 |    INDEX UNIQUE SCAN         | PK_DEPT |     1 |       |     0   (0)| 00:00:01 |  
  99. ----------------------------------------------------------------------------------------  
  100.   
  101. Predicate Information (identified by operation id):  
  102. ---------------------------------------------------  
  103.   
  104.    5 - filter("D"."LOC"='CHICAGO')  
  105.    6 - access("D"."DEPTNO"="V"."DEPTNO")  
  106.   
  107. SQL> select /*+ merge(v)*/ d.loc,v.avg_sal  
  108.   2  from dept d,( select deptno,avg(sal) avg_sal,min(sal) min_sal,max(sal) max_sal  
  109.   3   from emp group by deptno) v  
  110.   4  where d.deptno=v.deptno and d.loc='CHICAGO';  
  111.   
  112. 執行計劃  
  113. ----------------------------------------------------------  
  114. Plan hash value: 2941989041  
  115.   
  116. ----------------------------------------------------------------------------------------  
  117. | Id  | Operation                    | Name    | Rows  | Bytes | Cost (%CPU)| Time     |  
  118. ----------------------------------------------------------------------------------------  
  119. |   0 | SELECT STATEMENT             |         |     1 |    37 |    23  (83)| 00:00:01 |  
  120. |   1 |  NESTED LOOPS                |         |     1 |    37 |    23  (83)| 00:00:01 |  
  121. |   2 |   VIEW                       |         |     3 |    78 |    22  (87)| 00:00:01 |  
  122. |   3 |    HASH GROUP BY             |         |     3 |    21 |    22  (87)| 00:00:01 |  
  123. |   4 |     TABLE ACCESS FULL        | EMP     |   100K|   683K|     8  (63)| 00:00:01 |  
  124. |*  5 |   TABLE ACCESS BY INDEX ROWID| DEPT    |     1 |    11 |     1   (0)| 00:00:01 |  
  125. |*  6 |    INDEX UNIQUE SCAN         | PK_DEPT |     1 |       |     0   (0)| 00:00:01 |  
  126. ----------------------------------------------------------------------------------------  
  127.   
  128. Predicate Information (identified by operation id):  
  129. ---------------------------------------------------  
  130.   
  131.    5 - filter("D"."LOC"='CHICAGO')  
  132.    6 - access("D"."DEPTNO"="V"."DEPTNO")  

 

sql語句如果不能進行檢視合併,這個時候oracle查詢轉換器同樣會對該sql進行一種轉換,將外部查詢的謂詞推入(Predicate Pushing)到檢視中基表,從而能夠使用索引訪問,進行這種轉換也是為了獲得最優的執行計劃。需要注意的一點是,謂詞推入的前提是該sql中的檢視沒有進行檢視合併。

同樣以巢狀檢視為例:

  1. SQL> create index ind_emp_deptno on emp(deptno);  
  2.   
  3. 索引已建立。  
  4.   
  5. SQL> set autot traceonly explain  
  6. SQL> select d.loc,v.avg_sal  
  7.   2  from dept d,( select e.deptno,avg(e.sal) avg_sal,min(e.sal) min_sal,max(e.sal) max_sal  
  8.   3   from emp e group by e.deptno) v  
  9.   4  where d.deptno=v.deptno and v.deptno=20;  
  10.   
  11. 執行計劃  
  12. ----------------------------------------------------------  
  13. Plan hash value: 3947471307  
  14.   
  15. ------------------------------------------------------------------------------------------------  
  16. | Id  | Operation                     | Name           | Rows  | Bytes | Cost (%CPU)| Time     |  
  17. ------------------------------------------------------------------------------------------------  
  18. |   0 | SELECT STATEMENT              |                |     1 |    27 |     2   (0)| 00:00:01 |  
  19. |   1 |  HASH GROUP BY                |                |     1 |    27 |     2   (0)| 00:00:01 |  
  20. |   2 |   NESTED LOOPS                |                |     5 |   135 |     2   (0)| 00:00:01 |  
  21. |   3 |    TABLE ACCESS BY INDEX ROWID| DEPT           |     1 |    20 |     1   (0)| 00:00:01 |  
  22. |*  4 |     INDEX UNIQUE SCAN         | PK_DEPT        |     1 |       |     0   (0)| 00:00:01 |  
  23. |   5 |    TABLE ACCESS BY INDEX ROWID| EMP            |     5 |    35 |     1   (0)| 00:00:01 |  
  24. |*  6 |     INDEX RANGE SCAN          | IND_EMP_DEPTNO |     5 |       |     0   (0)| 00:00:01 |  
  25. ------------------------------------------------------------------------------------------------  
  26.   
  27. Predicate Information (identified by operation id):  
  28. ---------------------------------------------------  
  29.   
  30.    4 - access("D"."DEPTNO"=20)  
  31.    6 - access("E"."DEPTNO"=20)  
  32.   
  33. SQL> select /*+ no_merge(v) */d.loc,v.avg_sal  
  34.   2  from dept d,( select e.deptno,avg(e.sal) avg_sal,min(e.sal) min_sal,max(e.sal) max_sal  
  35.   3   from emp e group by e.deptno) v  
  36.   4  where d.deptno=v.deptno and v.deptno=20;  
  37.   
  38. 執行計劃  
  39. ----------------------------------------------------------  
  40. Plan hash value: 87641604  
  41.   
  42. -------------------------------------------------------------------------------------------------  
  43. | Id  | Operation                      | Name           | Rows  | Bytes | Cost (%CPU)| Time     |  
  44. -------------------------------------------------------------------------------------------------  
  45. |   0 | SELECT STATEMENT               |                |     1 |    37 |     3   (0)| 00:00:01 |  
  46. |   1 |  NESTED LOOPS                  |                |     1 |    37 |     3   (0)| 00:00:01 |  
  47. |   2 |   TABLE ACCESS BY INDEX ROWID  | DEPT           |     1 |    11 |     1   (0)| 00:00:01 |  
  48. |*  3 |    INDEX UNIQUE SCAN           | PK_DEPT        |     1 |       |     0   (0)| 00:00:01 |  
  49. |   4 |   VIEW                         |                |     1 |    26 |     2   (0)| 00:00:01 |  
  50. |   5 |    SORT GROUP BY               |                |     1 |     7 |     2   (0)| 00:00:01 |  
  51. |   6 |     TABLE ACCESS BY INDEX ROWID| EMP            |     5 |    35 |     2   (0)| 00:00:01 |  
  52. |*  7 |      INDEX RANGE SCAN          | IND_EMP_DEPTNO |     5 |       |     1   (0)| 00:00:01 |  
  53. -------------------------------------------------------------------------------------------------  
  54.   
  55. Predicate Information (identified by operation id):  
  56. ---------------------------------------------------  
  57.   
  58.    3 - access("D"."DEPTNO"=20)  
  59.    7 - access("E"."DEPTNO"=20)     --這裡將謂詞v.deptno=20推入到了基表e(emp),從而能夠使用索引訪問。  


還有一種轉換叫做join謂詞推入。  
通常情況下是不能透過基於索引的巢狀迴圈連線來訪問檢視的,因為檢視(與表不同)上沒有索引,而join謂詞推入能夠基於索引的巢狀迴圈連線來訪問該檢視 , 但是這樣的話也並不總是最優的;因為這同樣遵循當驅動行源資料量比較大時,hash 連線 或 sort-merge 連線 可能會帶來更好的效率。
以下型別的檢視支援(當不能檢視合併時才有可能推入)這一轉換:
    UNION ALL/UNION view
    Outer-joined view
    Anti-joined view
    Semi-joined view
    DISTINCT view
    GROUP-BY view


  1. SQL> create index ind_emp_dept_no on emp(deptno);  
  2.   
  3. 索引已建立。  
  4.   
  5. SQL> set autot traceonly explain  
  6. SQL> select /*+ no_merge(v)  */  d.loc,v.ename   
  7.   2  from dept d,( select  * from emp) v  
  8.   3  where d.deptno=v.deptno(+) ;  
  9.   
  10. 執行計劃  
  11. ----------------------------------------------------------  
  12. Plan hash value: 2615629228  
  13.   
  14. ----------------------------------------------------------------------------  
  15. | Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
  16. ----------------------------------------------------------------------------  
  17. |   0 | SELECT STATEMENT    |      |    14 |   434 |     7  (15)| 00:00:01 |  
  18. |*  1 |  HASH JOIN OUTER    |      |    14 |   434 |     7  (15)| 00:00:01 |  
  19. |   2 |   TABLE ACCESS FULL | DEPT |     4 |    44 |     3   (0)| 00:00:01 |  
  20. |   3 |   VIEW              |      |    14 |   280 |     3   (0)| 00:00:01 |  
  21. |   4 |    TABLE ACCESS FULL| EMP  |    14 |   126 |     3   (0)| 00:00:01 |  
  22. ----------------------------------------------------------------------------  
  23.   
  24. Predicate Information (identified by operation id):  
  25. ---------------------------------------------------  
  26.   
  27.    1 - access("D"."DEPTNO"="V"."DEPTNO"(+))  
  28.   
  29. --使用no_merge保證檢視不能合併,push_pred 使join謂詞推入  
  30. SQL> select /*+ no_merge(v) push_pred (v) */  d.loc,v.ename  
  31.   2  from dept d,( select  * from emp) v  
  32.   3  where d.deptno=v.deptno(+) ;  
  33.   
  34. 執行計劃  
  35. ----------------------------------------------------------  
  36. Plan hash value: 114584144  
  37.   
  38. -------------------------------------------------------------------------------------------------  
  39. | Id  | Operation                     | Name            | Rows  | Bytes | Cost (%CPU)| Time     |  
  40. -------------------------------------------------------------------------------------------------  
  41. |   0 | SELECT STATEMENT              |                 |    14 |   350 |    11   (0)| 00:00:01 |  
  42. |   1 |  NESTED LOOPS OUTER           |                 |    14 |   350 |    11   (0)| 00:00:01 |  
  43. |   2 |   TABLE ACCESS FULL           | DEPT            |     4 |    56 |     3   (0)| 00:00:01 |  
  44. |   3 |   VIEW PUSHED PREDICATE       |                 |     1 |    11 |     2   (0)| 00:00:01 |  
  45. |   4 |    TABLE ACCESS BY INDEX ROWID| EMP             |     5 |    60 |     2   (0)| 00:00:01 |  
  46. |*  5 |     INDEX RANGE SCAN          | IND_EMP_DEPT_NO |     5 |       |     1   (0)| 00:00:01 |  
  47. -------------------------------------------------------------------------------------------------  
  48.   
  49. Predicate Information (identified by operation id):  
  50. ---------------------------------------------------  
  51.   
  52.    5 - access("EMP"."DEPTNO"="D"."DEPTNO")   --join謂詞已推入到基表,並訪問基表的索引。  
  53.   
  54. SQL> select /*+ no_merge(v) no_push_pred (v) */  d.loc,v.ename  
  55.   2  from dept d,( select  * from emp) v  
  56.   3  where d.deptno=v.deptno(+) ;  
  57.   
  58. 執行計劃  
  59. ----------------------------------------------------------  
  60. Plan hash value: 2615629228  
  61.   
  62. ----------------------------------------------------------------------------  
  63. | Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
  64. ----------------------------------------------------------------------------  
  65. |   0 | SELECT STATEMENT    |      |    14 |   434 |     7  (15)| 00:00:01 |  
  66. |*  1 |  HASH JOIN OUTER    |      |    14 |   434 |     7  (15)| 00:00:01 |  
  67. |   2 |   TABLE ACCESS FULL | DEPT |     4 |    44 |     3   (0)| 00:00:01 |  
  68. |   3 |   VIEW              |      |    14 |   280 |     3   (0)| 00:00:01 |  
  69. |   4 |    TABLE ACCESS FULL| EMP  |    14 |   126 |     3   (0)| 00:00:01 |  
  70. ----------------------------------------------------------------------------  
  71.   
  72. Predicate Information (identified by operation id):  
  73. ---------------------------------------------------  
  74.   
  75.    1 - access("D"."DEPTNO"="V"."DEPTNO"(+))     

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

相關文章