oracle的查询转换之复杂视图合并

本文参考链接:https://blogs.oracle.com/optimizer/entry/optimizer_transformations_view_merging_part_2

Complex view merging, for distinct and group by views.
==》复杂视图合并是指视图定义中含有 distinct或group by的视图合并。

Delaying a group-by until after joins can result in a reduction in the data set on which the group-by operation is to be performed, if joins are filtering; on the other hand, early group-by can reduce the amount of data to be processed by subsequent joins or the joins could explode the amount of data to undergo group-by. The same is true for distinct operations. Because it is not always better to merge such a view, we choose whether to use this transformation in a cost-based manner. The two options - with and without view merging - are each costed by the optimizer, and we choose to merge the view only if it is cheaper to do so.
==》如果表连接能够有效的过滤数据,那么group by可以在视图合并的表连接后再做。
   如果group by能够有效过滤数据而视图合并的表连接不行,那么就要先做group by的操作。
   该原理同样适用于distinct的操作。
   因为复杂视图合并并不能总是获得最优化的执行计划。
   所以只有当复杂视图合并后的sql成本小于原sql的成本时,oracle才会执行复杂视图合并。
示例1:展示了含有group by视图语句
  1. create view cust_prod_totals_v as
  2. select sum(s.quantity_sold) total, s.cust_id, s.prod_id
  3. from sales s
  4. group by s.cust_id, s.prod_id;

  5. select c.cust_id, c.cust_first_name, c.cust_last_name, c.cust_email
  6. from customers c, products p, cust_prod_totals_v
  7. where c.country_id = 52790
  8. and c.cust_id = cust_prod_totals_v.cust_id
  9. and cust_prod_totals_v.total > 100
  10. and cust_prod_totals_v.prod_id = p.prod_id
  11. and p.prod_name = '256MB Memory Card';

  12. ----------------------------------------------------------
  13. Plan hash value: 263021282

  14. ---------------------------------------------------------------------------------------------------------------------
  15. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
  16. ---------------------------------------------------------------------------------------------------------------------
  17. | 0 | SELECT STATEMENT | | 1 | 101 | 517 (7)| 00:00:07 | | |
  18. | 1 | NESTED LOOPS | | | | | | | |
  19. | 2 | NESTED LOOPS | | 1 | 101 | 517 (7)| 00:00:07 | | |
  20. | 3 | NESTED LOOPS | | 1 | 56 | 516 (7)| 00:00:07 | | |
  21. | 4 | VIEW | CUST_PROD_TOTALS_V | 1 | 26 | 515 (7)| 00:00:07 | | |
  22. |* 5 | FILTER | | | | | | | |
  23. | 6 | HASH GROUP BY | | 1 | 12 | 515 (7)| 00:00:07 | | |
  24. | 7 | PARTITION RANGE ALL | | 918K| 10M| 489 (2)| 00:00:06 | 1 | 28 |
  25. | 8 | TABLE ACCESS FULL | SALES | 918K| 10M| 489 (2)| 00:00:06 | 1 | 28 |
  26. |* 9 | TABLE ACCESS BY INDEX ROWID| PRODUCTS | 1 | 30 | 1 (0)| 00:00:01 | | |
  27. |* 10 | INDEX UNIQUE SCAN | PRODUCTS_PK | 1 | | 0 (0)| 00:00:01 | | |
  28. |* 11 | INDEX UNIQUE SCAN | CUSTOMERS_PK | 1 | | 0 (0)| 00:00:01 | | |
  29. |* 12 | TABLE ACCESS BY INDEX ROWID | CUSTOMERS | 1 | 45 | 1 (0)| 00:00:01 | | |
  30. ---------------------------------------------------------------------------------------------------------------------
  31. Predicate Information (identified by operation id):
  32. ---------------------------------------------------
  33.    5 - filter(SUM("S"."QUANTITY_SOLD")>100)
  34.    9 - filter("P"."PROD_NAME"='256MB Memory Card')
  35.    省略部分...

==》这里步骤4出现了关键字view并且name列为‘CUST_PROD_TOTALS_V’,说明这里未做复杂合并。

示例2:在示例1的代码上使用了hint,强制走视图合并。
  1. select /*+ merge(cust_prod_totals_v) */ c.cust_id, c.cust_first_name, c.cust_last_name, c.cust_email
  2. from customers c, products p, cust_prod_totals_v
  3. where c.country_id = 52790
  4. and c.cust_id = cust_prod_totals_v.cust_id
  5. and cust_prod_totals_v.total > 100
  6. and cust_prod_totals_v.prod_id = p.prod_id
  7. and p.prod_name = '256MB Memory Card';

  8. Execution Plan
  9. ----------------------------------------------------------
  10. Plan hash value: 489274641

  11. ------------------------------------------------------------------------------------------------------------------------
  12. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
  13. ------------------------------------------------------------------------------------------------------------------------
  14. | 0 | SELECT STATEMENT | | 639 | 70929 | 829 (1)| 00:00:10 | | |
  15. |* 1 | FILTER | | | | | | | |
  16. | 2 | HASH GROUP BY | | 639 | 70929 | 829 (1)| 00:00:10 | | |
  17. |* 3 | HASH JOIN | | 12761 | 1383K| 828 (1)| 00:00:10 | | |
  18. | 4 | NESTED LOOPS | | | | | | | |
  19. | 5 | NESTED LOOPS | | 12762 | 672K| 422 (0)| 00:00:06 | | |
  20. |* 6 | TABLE ACCESS FULL | PRODUCTS | 1 | 42 | 3 (0)| 00:00:01 | | |
  21. | 7 | PARTITION RANGE ALL | | | | | | 1 | 28 |
  22. | 8 | BITMAP CONVERSION TO ROWIDS | | | | | | | |
  23. |* 9 | BITMAP INDEX SINGLE VALUE | SALES_PROD_BIX | | | | | 1 | 28 |
  24. | 10 | TABLE ACCESS BY LOCAL INDEX ROWID| SALES | 12762 | 149K| 422 (0)| 00:00:06 | 1 | 1 |
  25. |* 11 | TABLE ACCESS FULL | CUSTOMERS | 18693 | 1040K| 405 (1)| 00:00:05 | | |
  26. ------------------------------------------------------------------------------------------------------------------------
  27. Predicate Information (identified by operation id):
  28. ---------------------------------------------------
  29.    1 - filter(SUM("S"."QUANTITY_SOLD")>100)
  30.    3 - access("C"."CUST_ID"="S"."CUST_ID")
  31.    省略部分...
==》 这里HASH JOIN出现在了 HASH GROUP BY 操作之前,说明做了视图合并。
    但这里的成本值为829,大于未做视图合并时的517。这就是示例1未做视图合并的原因 
示例3:示例2的等价改写
  1. select c.cust_id, cust_first_name, cust_last_name, cust_email
  2. from customers c, products p, sales s
  3. where c.country_id = 52790
  4. and c.cust_id = s.cust_id
  5. and s.prod_id = p.prod_id
  6. and p.prod_name = '256MB Memory Card'
  7. group by s.cust_id, s.prod_id, p.rowid, c.rowid,
  8. c.cust_email, c.cust_last_name, c.cust_first_name, c.cust_id
  9. having sum(s.quantity_sold) > 100;
  10.   
  11.   Execution Plan
  12. ----------------------------------------------------------
  13. Plan hash value: 489274641

  14. ------------------------------------------------------------------------------------------------------------------------
  15. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
  16. ------------------------------------------------------------------------------------------------------------------------
  17. | 0 | SELECT STATEMENT | | 1 | 111 | 829 (1)| 00:00:10 | | |
  18. |* 1 | FILTER | | | | | | | |
  19. | 2 | HASH GROUP BY | | 1 | 111 | 829 (1)| 00:00:10 | | |
  20. |* 3 | HASH JOIN | | 12761 | 1383K| 828 (1)| 00:00:10 | | |
  21. | 4 | NESTED LOOPS | | | | | | | |
  22. | 5 | NESTED LOOPS | | 12762 | 672K| 422 (0)| 00:00:06 | | |
  23. |* 6 | TABLE ACCESS FULL | PRODUCTS | 1 | 42 | 3 (0)| 00:00:01 | | |
  24. | 7 | PARTITION RANGE ALL | | | | | | 1 | 28 |
  25. | 8 | BITMAP CONVERSION TO ROWIDS | | | | | | | |
  26. |* 9 | BITMAP INDEX SINGLE VALUE | SALES_PROD_BIX | | | | | 1 | 28 |
  27. | 10 | TABLE ACCESS BY LOCAL INDEX ROWID| SALES | 12762 | 149K| 422 (0)| 00:00:06 | 1 | 1 |
  28. |* 11 | TABLE ACCESS FULL | CUSTOMERS | 18693 | 1040K| 405 (1)| 00:00:05 | | |
  29. ------------------------------------------------------------------------------------------------------------------------
  30. Predicate Information (identified by operation id):
  31. ---------------------------------------------------
  32.    1 - filter(SUM("S"."QUANTITY_SOLD")>100)
  33.    3 - access("C"."CUST_ID"="S"."CUST_ID")
  34.    省略部分...
==》这里的执行计划和示例2是一致的。

接下来我们来看下含有distinc函数的复杂视图合并。
示例4:
  1. select c.cust_id, c.cust_first_name, c.cust_last_name, c.cust_email
  2. from customers c, products p,
  3. (select distinct s.cust_id, s.prod_id
  4. from sales s) cust_prod_v
  5. where c.country_id = 52790
  6. and c.cust_id = cust_prod_v.cust_id
  7. and cust_prod_v.prod_id = p.prod_id
  8. and p.prod_name = '256MB Memory Card';
  9. Execution Plan
  10. ----------------------------------------------------------
  11. Plan hash value: 2262313492

  12. --------------------------------------------------------------------------------------------------------------------------------
  13. | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
  14. --------------------------------------------------------------------------------------------------------------------------------
  15. | 0 | SELECT STATEMENT | | 12761 | 797K| | 1141 (1)| 00:00:14 | | |
  16. | 1 | VIEW | VM_NWVW_1 | 12761 | 797K| | 1141 (1)| 00:00:14 | | |
  17. | 2 | HASH UNIQUE | | 12761 | 1345K| 1584K| 1141 (1)| 00:00:14 | | |
  18. |* 3 | HASH JOIN | | 12761 | 1345K| | 828 (1)| 00:00:10 | | |
  19. | 4 | NESTED LOOPS | | | | | | | | |
  20. | 5 | NESTED LOOPS | | 12762 | 635K| | 422 (0)| 00:00:06 | | |
  21. |* 6 | TABLE ACCESS FULL | PRODUCTS | 1 | 42 | | 3 (0)| 00:00:01 | | |
  22. | 7 | PARTITION RANGE ALL | | | | | | | 1 | 28 |
  23. | 8 | BITMAP CONVERSION TO ROWIDS | | | | | | | | |
  24. |* 9 | BITMAP INDEX SINGLE VALUE | SALES_PROD_BIX | | | | | | 1 | 28 |
  25. | 10 | TABLE ACCESS BY LOCAL INDEX ROWID| SALES | 12762 | 112K| | 422 (0)| 00:00:06 | 1 | 1 |
  26. |* 11 | TABLE ACCESS FULL | CUSTOMERS | 18693 | 1040K| | 405 (1)| 00:00:05 | | |
  27. --------------------------------------------------------------------------------------------------------------------------------
  28. Predicate Information (identified by operation id):
  29. ---------------------------------------------------
  30.    3 - access("C"."CUST_ID"="S"."CUST_ID")
  31.    6 - filter("P"."PROD_NAME"='256MB Memory Card')
  32.    省略部分...
So why do we still have a view after we've supposedly merged the view? The new view is what we call a "projection view". When we merge the view, we move the distinct to the outer query block. But when we move the distinct, we have to add several additional columns, in order to maintain semantic equivalence with the original query. So we put all of that into a new view, so we can select out just the columns we want in the outer query block's select list. 

==》这段英文描述解释了步骤1出现了关键字view且name列为‘VM_NWVW_1’的原因。
大致意思是说,做视图合并时为了保证语义的完整性需要添加额外的列,将查询列和新增列放在一个查询块中。
我们最后只需要在外部查询中选出我们所需要的列即可。
示例5: 示例4的等价改写
  1. select VM_NWVW_1.cust_id, VM_NWVW_1.cust_first_name, VM_NWVW_1.cust_last_name, VM_NWVW_1.cust_email
  2. from
  3. (select distinct s.cust_id as cust_id,
  4.        c.cust_first_name as cust_first_name,
  5.      c.cust_last_name as cust_last_name ,
  6.      c.cust_email as cust_email,
  7.      c.rowid,
  8.      p.rowid
  9. from customers c, products p,sales s
  10. where c.country_id = 52790
  11. and c.cust_id = s.cust_id
  12. and s.prod_id = p.prod_id
  13. and p.prod_name = '256MB Memory Card') VM_NWVW_1;
  14. Execution Plan
  15. ----------------------------------------------------------
  16. Plan hash value: 2322365470

  17. --------------------------------------------------------------------------------------------------------------------------------
  18. | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
  19. --------------------------------------------------------------------------------------------------------------------------------
  20. | 0 | SELECT STATEMENT | | 12761 | 797K| | 1141 (1)| 00:00:14 | | |
  21. | 1 | VIEW | | 12761 | 797K| | 1141 (1)| 00:00:14 | | |
  22. | 2 | HASH UNIQUE | | 12761 | 1345K| 1584K| 1141 (1)| 00:00:14 | | |
  23. |* 3 | HASH JOIN | | 12761 | 1345K| | 828 (1)| 00:00:10 | | |
  24. | 4 | NESTED LOOPS | | | | | | | | |
  25. | 5 | NESTED LOOPS | | 12762 | 635K| | 422 (0)| 00:00:06 | | |
  26. |* 6 | TABLE ACCESS FULL | PRODUCTS | 1 | 42 | | 3 (0)| 00:00:01 | | |
  27. | 7 | PARTITION RANGE ALL | | | | | | | 1 | 28 |
  28. | 8 | BITMAP CONVERSION TO ROWIDS | | | | | | | | |
  29. |* 9 | BITMAP INDEX SINGLE VALUE | SALES_PROD_BIX | | | | | | 1 | 28 |
  30. | 10 | TABLE ACCESS BY LOCAL INDEX ROWID| SALES | 12762 | 112K| | 422 (0)| 00:00:06 | 1 | 1 |
  31. |* 11 | TABLE ACCESS FULL | CUSTOMERS | 18693 | 1040K| | 405 (1)| 00:00:05 | | |
  32. --------------------------------------------------------------------------------------------------------------------------------
  33. Predicate Information (identified by operation id):
  34. ---------------------------------------------------
  35.    3 - access("C"."CUST_ID"="S"."CUST_ID")
  36.    6 - filter("P"."PROD_NAME"='256MB Memory Card')
  37.    省略部分...
==》这里可以看到除了步骤1view的name列为空外,其它都示例4的执行计划一致。

最后介绍2个控制视图合并的隐含擦参数
_optimizer_cost_based_transformation 
默认值为LINEAR,及根据转换前后的成本对比来决定是否视图合并。
若将值设置为off,则表示能做视图合并的一定做视图合并而不考虑成本。
_complex_view_merging 
默认值为TRUE,表示默认情况下允许复杂视图合并。
 
end!

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/25923810/viewspace-2130036/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/25923810/viewspace-2130036/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值