- 视图合并,视图合并是一种能将内嵌或存储式视图展开为能够独立分析或者与查询剩余部分合成总体执行计划的独立查询的转换,改写后的语句基本上不包含视图。视图合并常常发生在当外部查询块的谓语包括下列项的时候。
能够在另一个查询块的索引中使用的列
能够在另一个查询块的分区截断中使用的列
在一个联结视图中能够限制返回行数的条件
.
-
select * from orders o,(select sales_rep_id from orders) o_view where o.sales_rep_id=o_view.sales_rep_id(+) and o.order_total>10000 Plan hash value: 1066515912 ------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | ------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 368 |00:00:00.01 | 81 | | 1 | NESTED LOOPS OUTER| | 1 | 635 | 368 |00:00:00.01 | 81 | |* 2 | TABLE ACCESS FULL| ORDERS | 1 | 101 | 67 |00:00:00.01 | 32 | |* 3 | INDEX RANGE SCAN | ORD_SALES_REP_IX | 67 | 6 | 341 |00:00:00.01 | 49 | ------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("O"."ORDER_TOTAL">10000) 3 - access("O"."SALES_REP_ID"="SALES_REP_ID") filter("SALES_REP_ID" IS NOT NULL) 23 rows selected
不视图合并:
-
select /*+ no_merge(o_view) */* from orders o,(select sales_rep_id from orders) o_view where o.sales_rep_id=o_view.sales_rep_id(+) and o.order_total>10000 Plan hash value: 2722607751 ------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem | ------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 368 |00:00:00.01 | 37 | | | | |* 1 | HASH JOIN OUTER | | 1 | 635 | 368 |00:00:00.01 | 37 | 1034K| 1034K| 879K (0)| |* 2 | TABLE ACCESS FULL | ORDERS | 1 | 101 | 67 |00:00:00.01 | 7 | | | | | 3 | VIEW | | 1 | 105 | 105 |00:00:00.01 | 30 | | | | | 4 | TABLE ACCESS FULL| ORDERS | 1 | 105 | 105 |00:00:00.01 | 30 | | | | ------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("O"."SALES_REP_ID"="O_VIEW"."SALES_REP_ID") 2 - filter("O"."ORDER_TOTAL">10000) 24 rows selected.
还有其他一些情况,如果出现,也会阻止视图合并的发生,如果一个查询块中包含解析函数或聚合函数,集合运算(UNION,INTERSECT,MINUS),ORDER BY子句或者使用ROWNUM,视图合并将会被禁止或限制。
-
select e1.last_name,e1.salary,v.avg_salary from employees e1,(select department_id,avg(salary)avg_salary from employees e2 group by department_id) v where e1.department_id=v.department_id and e1.salary>v.avg_salary Plan hash value: 2695105989 ----------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem | ----------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 38 |00:00:00.01 | 17 | | | | |* 1 | HASH JOIN | | 1 | 17 | 38 |00:00:00.01 | 17 | 1421K| 1421K| 916K (0)| | 2 | VIEW | | 1 | 11 | 12 |00:00:00.01 | 7 | | | | | 3 | HASH GROUP BY | | 1 | 11 | 12 |00:00:00.01 | 7 | 1106K| 1106K| 1766K (0)| | 4 | TABLE ACCESS FULL| EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 7 | | | | | 5 | TABLE ACCESS FULL | EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 10 | | | | ----------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("E1"."DEPARTMENT_ID"="V"."DEPARTMENT_ID") filter("E1"."SALARY">"V"."AVG_SALARY") Note ----- - this is an adaptive plan
视图合并由以下参数决定:
子查询解嵌套:
子查询解嵌套与视图合并的相似之处在于子查询也是通过一个单独的查询块来表示的,可合并的视图与可以解嵌套的查询之间主要的区别在于他们的位置是不同的。子查询位于where子句,由查询转换器解嵌套的审查。最典型的转换就是讲子查询转变为表联结,如果一个子查询么有解嵌套,将会为它生成一个独立的子计划并作为总的执行计划的一部分按照优化执行速度的次序进行。当子查询不相关的时候,转换查询是非常直接的。
-
SQL> select * from hr.employees where department_id in (select department_id from hr.departments); 106 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 1445457117 ------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 106 | 7314 | 3 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| EMPLOYEES | 106 | 7314 | 3 (0)| 00:00:01 |
使用NO_UNNEST提示:
-
select employee_id,last_name,salary,department_id from employees where department_id in(select /*+ no_unnest */ department_id from departments where location_id>1700) Plan hash value: 4233807898 --------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | --------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 38 |00:00:00.02 | 32 | 1 | |* 1 | FILTER | | 1 | | 38 |00:00:00.02 | 32 | 1 | | 2 | TABLE ACCESS FULL | EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 10 | 0 | |* 3 | TABLE ACCESS BY INDEX ROWID| DEPARTMENTS | 12 | 1 | 4 |00:00:00.02 | 22 | 1 | |* 4 | INDEX UNIQUE SCAN | DEPT_ID_PK | 12 | 1 | 11 |00:00:00.02 | 11 | 1 | --------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter( IS NOT NULL) 3 - filter("LOCATION_ID">1700) 4 - access("DEPARTMENT_ID"=:B1) 25 rows selected
select outer.employee_id,outer.last_name,outer.salary,outer.department_i
d from employees outer where outer.salary>(select avg(inner.salary) from employees inner where inner.department_id=outer.department_id) Plan hash value: 2167610409 ----------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem | ----------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 38 |00:00:00.01 | 17 | | | | |* 1 | HASH JOIN | | 1 | 38 | 38 |00:00:00.01 | 17 | 1321K| 1321K| 1067K (0)| | 2 | VIEW | VW_SQ_1 | 1 | 11 | 12 |00:00:00.01 | 7 | | | | | 3 | HASH GROUP BY | | 1 | 11 | 12 |00:00:00.01 | 7 | 1106K| 1106K| 986K (0)| | 4 | TABLE ACCESS FULL| EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 7 | | | | | 5 | TABLE ACCESS FULL | EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 10 | | | | ----------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("ITEM_1"="OUTER"."DEPARTMENT_ID") filter("OUTER"."SALARY">"AVG(INNER.SALARY)") Note ----- - statistics feedback used for this statement - this is an adaptive plan 30 rows selected.
谓词推入:
谓语前推用来将谓语从一个内含查询中应用到不可合并的查询块中。目标就是允许索引的使用或者让其他对于数据集的筛选在查询中能够更早地进行,一般来说,将不需要的数据行尽可能早地过滤都是个好主意,如果一个谓语可以通过将它前推到不可合并查询块中更早的执行,在剩下的执行计划中所需要抓取的数据就会更少,更少的数据意味着要做的事情也更少。
select e1.last_name,e1.salary,v.avg_salary from employees e1,(select department_id,avg(salary)avg_salary from employees e2 group by department_id)v where e1.department_id=v.department_id and e1.salary>v.avg_salary and e1.department_id=60 Plan hash value: 3420982931 -------------------------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem | -------------------------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 2 |00:00:00.01 | 6 | | | | | 1 | NESTED LOOPS | | 1 | 1 | 2 |00:00:00.01 | 6 | | | | | 2 | NESTED LOOPS | | 1 | | 5 |00:00:00.01 | 4 | | | | | 3 | VIEW | | 1 | 5 | 1 |00:00:00.01 | 2 | | | | | 4 | HASH GROUP BY | | 1 | 5 | 1 |00:00:00.01 | 2 | 1116K| 1116K| 489K (0)| | 5 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 1 | 5 | 5 |00:00:00.01 | 2 | | | | |* 6 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 1 | 5 | 5 |00:00:00.01 | 1 | | | | |* 7 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 1 | 5 | 5 |00:00:00.01 | 2 | | | | |* 8 | TABLE ACCESS BY INDEX ROWID | EMPLOYEES | 5 | 1 | 2 |00:00:00.01 | 2 | | | | -------------------------------------------------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 6 - access("DEPARTMENT_ID"=60) 7 - access("E1"."DEPARTMENT_ID"=60) 8 - filter("E1"."SALARY">"V"."AVG_SALARY") Note ----- - this is an adaptive plan 34 rows selected.
ID=6被推入视图中先执行,
使用rownum禁止谓词推入:
select e1.last_name,e1.salary,v.avg_salary from employees e1,(select department_id,avg(salary)avg_salary from employees e2 where rownum>1 group by department_id)v where e1.department_id=v.department_id and e1.salary>v.avg_salary and e1.department_id=60 Plan hash value: 3724319777 ------------------------------------------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem | ------------------------------------------------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | | 0 |00:00:00.01 | 9 | | | |* 1 | HASH JOIN | | 1 | 3 | 0 |00:00:00.01 | 9 | 1519K| 1519K| 288K (0)| | 2 | JOIN FILTER CREATE | :BF0000 | 1 | 5 | 5 |00:00:00.01 | 2 | | | | 3 | TABLE ACCESS BY INDEX ROWID BATCHED| EMPLOYEES | 1 | 5 | 5 |00:00:00.01 | 2 | | | |* 4 | INDEX RANGE SCAN | EMP_DEPARTMENT_IX | 1 | 5 | 5 |00:00:00.01 | 1 | | | |* 5 | VIEW | | 1 | 11 | 0 |00:00:00.01 | 7 | | | | 6 | HASH GROUP BY | | 1 | 11 | 0 |00:00:00.01 | 7 | 1484K| 1484K | | 7 | JOIN FILTER USE | :BF0000 | 1 | 107 | 0 |00:00:00.01 | 7 | | | | 8 | COUNT | | 1 | | 0 |00:00:00.01 | 7 | | | |* 9 | FILTER | | 1 | | 0 |00:00:00.01 | 7 | | | | 10 | TABLE ACCESS FULL | EMPLOYEES | 1 | 107 | 107 |00:00:00.01 | 7 | | | ------------------------------------------------------------------------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("E1"."DEPARTMENT_ID"="V"."DEPARTMENT_ID") filter("E1"."SALARY">"V"."AVG_SALARY") 4 - access("E1"."DEPARTMENT_ID"=60) 5 - filter("V"."DEPARTMENT_ID"=60) 9 - filter(ROWNUM>1) 34 rows selected.
使用物化视图进行查询重写:
SQL> select p.prod_id,p.prod_name,t.time_id,t.week_ending_day,s.channel_id,s.promo_id,s.cust_id,s.amount_sold from sales s,products p,times t where s.time_id=t.time_id and s.prod_id=p.prod_id; Execution Plan ---------------------------------------------------------- Plan hash value: 187439137 ---------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | ---------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 918K| 65M| 542 (3)| 00:00:01 | | | |* 1 | HASH JOIN | | 918K| 65M| 542 (3)| 00:00:01 | | | | 2 | PART JOIN FILTER CREATE | :BF0000 | 1826 | 29216 | 18 (0)| 00:00:01 | | | | 3 | TABLE ACCESS FULL | TIMES | 1826 | 29216 | 18 (0)| 00:00:01 | | | |* 4 | HASH JOIN | | 918K| 51M| 522 (2)| 00:00:01 | | | | 5 | TABLE ACCESS FULL | PRODUCTS | 72 | 2160 | 3 (0)| 00:00:01 | | | | 6 | PARTITION RANGE JOIN-FILTER| | 918K| 25M| 517 (2)| 00:00:01 |:BF0000|:BF0000| | 7 | TABLE ACCESS FULL | SALES | 918K| 25M| 517 (2)| 00:00:01 |:BF0000|:BF0000| ---------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("S"."TIME_ID"="T"."TIME_ID") 4 - access("S"."PROD_ID"="P"."PROD_ID") Note ----- - this is an adaptive plan
SQL> create materialized view sales_time_product_mv enable query rewrite as select p.prod_id,p.prod_name,t.time_id,t.week_ending_day,s.channel_id,s.promo_id,s.cust_id,s.amount_sold from sales s,products p,times t where s.time_id=t.time_id and s.prod_id=p.prod_id SQL> select /*+ rewrite(sales_time_product_mv) */p.prod_id,p.prod_name,t.time_id,t.week_ending_day,s.channel_id,s.promo_id,s.cust_id,s.amount_sold from sales s,products p,times t where s.time_id=t.time_id and s.prod_id=p.prod_id; Execution Plan ---------------------------------------------------------- Plan hash value: 663088863 ------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 918K| 52M| 2334 (1)| 00:00:01 | | 1 | MAT_VIEW REWRITE ACCESS FULL| SALES_TIME_PRODUCT_MV | 918K| 52M| 2334 (1)| 00:00:01 | ------------------------------------------------------------------------------------------------------
时间: 2024-08-09 06:35:33