本文参考链接: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视图语句
- 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;
-
- 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 = '256MB Memory Card';
-
- ----------------------------------------------------------
- Plan hash value: 263021282
-
- ---------------------------------------------------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
- ---------------------------------------------------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 1 | 101 | 517 (7)| 00:00:07 | | |
- | 1 | NESTED LOOPS | | | | | | | |
- | 2 | NESTED LOOPS | | 1 | 101 | 517 (7)| 00:00:07 | | |
- | 3 | NESTED LOOPS | | 1 | 56 | 516 (7)| 00:00:07 | | |
- | 4 | VIEW | CUST_PROD_TOTALS_V | 1 | 26 | 515 (7)| 00:00:07 | | |
- |* 5 | FILTER | | | | | | | |
- | 6 | HASH GROUP BY | | 1 | 12 | 515 (7)| 00:00:07 | | |
- | 7 | PARTITION RANGE ALL | | 918K| 10M| 489 (2)| 00:00:06 | 1 | 28 |
- | 8 | TABLE ACCESS FULL | SALES | 918K| 10M| 489 (2)| 00:00:06 | 1 | 28 |
- |* 9 | TABLE ACCESS BY INDEX ROWID| PRODUCTS | 1 | 30 | 1 (0)| 00:00:01 | | |
- |* 10 | INDEX UNIQUE SCAN | PRODUCTS_PK | 1 | | 0 (0)| 00:00:01 | | |
- |* 11 | INDEX UNIQUE SCAN | CUSTOMERS_PK | 1 | | 0 (0)| 00:00:01 | | |
- |* 12 | TABLE ACCESS BY INDEX ROWID | CUSTOMERS | 1 | 45 | 1 (0)| 00:00:01 | | |
- ---------------------------------------------------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 5 - filter(SUM("S"."QUANTITY_SOLD")>100)
- 9 - filter("P"."PROD_NAME"='256MB Memory Card')
- 省略部分...
==》这里步骤4出现了关键字view并且name列为‘CUST_PROD_TOTALS_V’,说明这里未做复杂合并。
示例2:在示例1的代码上使用了hint,强制走视图合并。- select /*+ merge(cust_prod_totals_v) */ 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 = '256MB Memory Card';
-
- Execution Plan
- ----------------------------------------------------------
- Plan hash value: 489274641
-
- ------------------------------------------------------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
- ------------------------------------------------------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 639 | 70929 | 829 (1)| 00:00:10 | | |
- |* 1 | FILTER | | | | | | | |
- | 2 | HASH GROUP BY | | 639 | 70929 | 829 (1)| 00:00:10 | | |
- |* 3 | HASH JOIN | | 12761 | 1383K| 828 (1)| 00:00:10 | | |
- | 4 | NESTED LOOPS | | | | | | | |
- | 5 | NESTED LOOPS | | 12762 | 672K| 422 (0)| 00:00:06 | | |
- |* 6 | TABLE ACCESS FULL | PRODUCTS | 1 | 42 | 3 (0)| 00:00:01 | | |
- | 7 | PARTITION RANGE ALL | | | | | | 1 | 28 |
- | 8 | BITMAP CONVERSION TO ROWIDS | | | | | | | |
- |* 9 | BITMAP INDEX SINGLE VALUE | SALES_PROD_BIX | | | | | 1 | 28 |
- | 10 | TABLE ACCESS BY LOCAL INDEX ROWID| SALES | 12762 | 149K| 422 (0)| 00:00:06 | 1 | 1 |
- |* 11 | TABLE ACCESS FULL | CUSTOMERS | 18693 | 1040K| 405 (1)| 00:00:05 | | |
- ------------------------------------------------------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - filter(SUM("S"."QUANTITY_SOLD")>100)
- 3 - access("C"."CUST_ID"="S"."CUST_ID")
- 省略部分...
但这里的成本值为829,大于未做视图合并时的517。这就是示例1未做视图合并的原因。
示例3:示例2的等价改写
- 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 = '256MB Memory Card'
- 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;
-
- Execution Plan
- ----------------------------------------------------------
- Plan hash value: 489274641
-
- ------------------------------------------------------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
- ------------------------------------------------------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 1 | 111 | 829 (1)| 00:00:10 | | |
- |* 1 | FILTER | | | | | | | |
- | 2 | HASH GROUP BY | | 1 | 111 | 829 (1)| 00:00:10 | | |
- |* 3 | HASH JOIN | | 12761 | 1383K| 828 (1)| 00:00:10 | | |
- | 4 | NESTED LOOPS | | | | | | | |
- | 5 | NESTED LOOPS | | 12762 | 672K| 422 (0)| 00:00:06 | | |
- |* 6 | TABLE ACCESS FULL | PRODUCTS | 1 | 42 | 3 (0)| 00:00:01 | | |
- | 7 | PARTITION RANGE ALL | | | | | | 1 | 28 |
- | 8 | BITMAP CONVERSION TO ROWIDS | | | | | | | |
- |* 9 | BITMAP INDEX SINGLE VALUE | SALES_PROD_BIX | | | | | 1 | 28 |
- | 10 | TABLE ACCESS BY LOCAL INDEX ROWID| SALES | 12762 | 149K| 422 (0)| 00:00:06 | 1 | 1 |
- |* 11 | TABLE ACCESS FULL | CUSTOMERS | 18693 | 1040K| 405 (1)| 00:00:05 | | |
- ------------------------------------------------------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - filter(SUM("S"."QUANTITY_SOLD")>100)
- 3 - access("C"."CUST_ID"="S"."CUST_ID")
- 省略部分...
接下来我们来看下含有distinc函数的复杂视图合并。
示例4:
- 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 = '256MB Memory Card';
- Execution Plan
- ----------------------------------------------------------
- Plan hash value: 2262313492
-
- --------------------------------------------------------------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
- --------------------------------------------------------------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 12761 | 797K| | 1141 (1)| 00:00:14 | | |
- | 1 | VIEW | VM_NWVW_1 | 12761 | 797K| | 1141 (1)| 00:00:14 | | |
- | 2 | HASH UNIQUE | | 12761 | 1345K| 1584K| 1141 (1)| 00:00:14 | | |
- |* 3 | HASH JOIN | | 12761 | 1345K| | 828 (1)| 00:00:10 | | |
- | 4 | NESTED LOOPS | | | | | | | | |
- | 5 | NESTED LOOPS | | 12762 | 635K| | 422 (0)| 00:00:06 | | |
- |* 6 | TABLE ACCESS FULL | PRODUCTS | 1 | 42 | | 3 (0)| 00:00:01 | | |
- | 7 | PARTITION RANGE ALL | | | | | | | 1 | 28 |
- | 8 | BITMAP CONVERSION TO ROWIDS | | | | | | | | |
- |* 9 | BITMAP INDEX SINGLE VALUE | SALES_PROD_BIX | | | | | | 1 | 28 |
- | 10 | TABLE ACCESS BY LOCAL INDEX ROWID| SALES | 12762 | 112K| | 422 (0)| 00:00:06 | 1 | 1 |
- |* 11 | TABLE ACCESS FULL | CUSTOMERS | 18693 | 1040K| | 405 (1)| 00:00:05 | | |
- --------------------------------------------------------------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 3 - access("C"."CUST_ID"="S"."CUST_ID")
- 6 - filter("P"."PROD_NAME"='256MB Memory Card')
- 省略部分...
==》这段英文描述解释了步骤1出现了关键字view且name列为‘VM_NWVW_1’的原因。
大致意思是说,做视图合并时为了保证语义的完整性需要添加额外的列,将查询列和新增列放在一个查询块中。
我们最后只需要在外部查询中选出我们所需要的列即可。
示例5: 示例4的等价改写
- select VM_NWVW_1.cust_id, VM_NWVW_1.cust_first_name, VM_NWVW_1.cust_last_name, VM_NWVW_1.cust_email
- from
- (select distinct s.cust_id as cust_id,
- c.cust_first_name as cust_first_name,
- c.cust_last_name as cust_last_name ,
- c.cust_email as cust_email,
- c.rowid,
- p.rowid
- 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 = '256MB Memory Card') VM_NWVW_1;
- Execution Plan
- ----------------------------------------------------------
- Plan hash value: 2322365470
-
- --------------------------------------------------------------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
- --------------------------------------------------------------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 12761 | 797K| | 1141 (1)| 00:00:14 | | |
- | 1 | VIEW | | 12761 | 797K| | 1141 (1)| 00:00:14 | | |
- | 2 | HASH UNIQUE | | 12761 | 1345K| 1584K| 1141 (1)| 00:00:14 | | |
- |* 3 | HASH JOIN | | 12761 | 1345K| | 828 (1)| 00:00:10 | | |
- | 4 | NESTED LOOPS | | | | | | | | |
- | 5 | NESTED LOOPS | | 12762 | 635K| | 422 (0)| 00:00:06 | | |
- |* 6 | TABLE ACCESS FULL | PRODUCTS | 1 | 42 | | 3 (0)| 00:00:01 | | |
- | 7 | PARTITION RANGE ALL | | | | | | | 1 | 28 |
- | 8 | BITMAP CONVERSION TO ROWIDS | | | | | | | | |
- |* 9 | BITMAP INDEX SINGLE VALUE | SALES_PROD_BIX | | | | | | 1 | 28 |
- | 10 | TABLE ACCESS BY LOCAL INDEX ROWID| SALES | 12762 | 112K| | 422 (0)| 00:00:06 | 1 | 1 |
- |* 11 | TABLE ACCESS FULL | CUSTOMERS | 18693 | 1040K| | 405 (1)| 00:00:05 | | |
- --------------------------------------------------------------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 3 - access("C"."CUST_ID"="S"."CUST_ID")
- 6 - filter("P"."PROD_NAME"='256MB Memory Card')
- 省略部分...
最后介绍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/