1.定义
The join predicate pushdown (JPPD) transformation allows a view to be joined with index-based nested-loop join method, which may provide a more optimal alternative. In the join predicate pushdown transformation, the view remains a separate query block, but it contains the join predicate, which is pushed down from its containing query block into the view. The view thus becomes correlated and must be evaluated for each row of the outer query block. These pushed-down join predicates, once inside the view, open up new index access paths on the base tables inside the view; this allows the view to be joined with index-based nested-loop join method, thereby enabling the optimizer to select an efficient execution plan.At the first step, Oracle tries to merge the view. This is called view merging . When the view merging is not possible, Oracle tries to push the predicates into the view. Oracle pushes not only simple predicates, but also join predicates. PUSH_PRED hint controls the join predicate pushing.
2.分类
JPPD - join predicate push-down
OJPPD - old-style (non-cost-based) JPPD
------------------------------ ---------- ------------------------------------------------------------
_push_join_predicate TRUE enable pushing join predicate inside a view
hint:push_pred/no_push_pred
------------------------------ ---------- ------------------------------------------------------------
_optimizer_extend_jppd_view_types TRUE join pred pushdown on group-by, distinct, semi-/anti-joined view
即视图需要满足:
由于视图带有union all,所以不能做视图合并,但是满足了JPPD的条件
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20 | 1900 | 42 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 20 | 1900 | 42 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL | T | 10 | 130 | 2 (0)| 00:00:01 |
| 3 | VIEW | | 1 | 82 | 4 (0)| 00:00:01 |
| 4 | UNION ALL PUSHED PREDICATE | | | | | |
| 5 | TABLE ACCESS BY INDEX ROWID| LXY | 1 | 31 | 2 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | I1 | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| LXY_1 | 1 | 31 | 2 (0)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | I2 | 1 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SB
2 - SB / T@SB
3 - SET$5715CE2E / V@SB
4 - SET$5715CE2E
5 - SEL$E32B9D82 / LXY@NB
6 - SEL$E32B9D82 / LXY@NB
7 - SEL$9113C594 / LXY_1@SEL$1
8 - SEL$9113C594 / LXY_1@SEL$1
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
INDEX_RS_ASC(@"SEL$E32B9D82" "LXY"@"NB" ("LXY"."OBJECT_ID"))
INDEX_RS_ASC(@"SEL$9113C594" "LXY_1"@"SEL$1" ("LXY_1"."OBJECT_ID"))
USE_NL(@"SB" "V"@"SB")
LEADING(@"SB" "T"@"SB" "V"@"SB")
NO_ACCESS(@"SB" "V"@"SB")
FULL(@"SB" "T"@"SB")
OUTLINE(@"SB")
OUTLINE(@"SET$1")
OUTLINE(@"SEL$1")
OUTLINE(@"NB")
OUTLINE_LEAF(@"SB")
PUSH_PRED(@"SB" "V"@"SB" 1)
OUTLINE_LEAF(@"SET$5715CE2E")
OUTLINE_LEAF(@"SEL$9113C594")
OUTLINE_LEAF(@"SEL$E32B9D82")
ALL_ROWS
DB_VERSION('11.2.0.4')
OPTIMIZER_FEATURES_ENABLE('11.2.0.4')
IGNORE_OPTIM_EMBEDDED_HINTS
END_OUTLINE_DATA
*/
Predicate Information (identified by operation id):
---------------------------------------------------
6 - access("LXY"."OBJECT_ID"="T"."A")
8 - access("LXY_1"."OBJECT_ID"="T"."A")
很明显,CBO对该sql做了视图合并,从10053可以看到更详细的信息
***********************************
Cost-Based Join Predicate Push-down
***********************************
JPPD: Checking validity of push-down in query block SB (#1)
JPPD: Checking validity of push-down from query block SB (#1) to query block SET$1 (#2)
JPPD: Passed validity checks
JPPD: JPPD: Pushdown from query block SB (#1) passed validity checks.
Join-Predicate push-down on query block SB (#1)
JPPD: Using search type: linear
JPPD: Considering join predicate push-down
JPPD: Performing join predicate push-down (no transformation phase) from query block SB (#1) to query block SET$1 (#2)
...
JPPD: Updated best state, Cost = 106.38
JPPD: Performing join predicate push-down (candidate phase) from query block SB (#1) to query block SET$1 (#2)
JPPD: Pushing predicate "T"."A"="V"."OBJECT_ID"
from query block SB (#1) to query block SET$1 (#2)
JPPD: Push dest of pred 0x8a74b4a8 is qb 0x8a74dff0:query block SET$1 (#2)
JPPD: Push dest of pred 0x8a4d3f98 is qb 0x8a74dff0:query block SET$1 (#2)
...
JPPD: Updated best state, Cost = 42.01
OJPPD - old-style (non-cost-based) JPPD
1)JPPD:
10gR2之后,jppd是基于cost的,不仅需要满足_push_join_predicate=true和连接的视图满足_optimizer_extend_jppd_view_types的类型,且转换后cost要小于不转换的cost。2)OJPPD
10gR2之前,jppd是启发式转换,现在叫ojppd,也就是不计成本的。10gR2后如果要启用OJPPD,需要关闭_optimizer_cost_based_transformation或者_optimizer_push_pred_cost_based3.参数
KSPPINM KSPPSTVL KSPPDESC------------------------------ ---------- ------------------------------------------------------------
_push_join_predicate TRUE enable pushing join predicate inside a view
hint:push_pred/no_push_pred
4.限制
KSPPINM KSPPSTVL KSPPDESC------------------------------ ---------- ------------------------------------------------------------
_optimizer_extend_jppd_view_types TRUE join pred pushdown on group-by, distinct, semi-/anti-joined view
即视图需要满足:
- UNION ALL/UNION view
- Outer-joined view
- Anti-joined view
- Semi-joined view
- DISTINCT view
- GROUP-BY view
5.测试
sql文本:
- SELECT /*+ qb_name(sb)*/
- t.a, v.object_name, v.object_type
- FROM t,
- (SELECT /*+ qb_name(nb)*/* FROM lxy
- UNION ALL
- SELECT * FROM lxy_1) v
- WHERE t.a = v.object_id;
执行计划:
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20 | 1900 | 42 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 20 | 1900 | 42 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL | T | 10 | 130 | 2 (0)| 00:00:01 |
| 3 | VIEW | | 1 | 82 | 4 (0)| 00:00:01 |
| 4 | UNION ALL PUSHED PREDICATE | | | | | |
| 5 | TABLE ACCESS BY INDEX ROWID| LXY | 1 | 31 | 2 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | I1 | 1 | | 1 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID| LXY_1 | 1 | 31 | 2 (0)| 00:00:01 |
|* 8 | INDEX RANGE SCAN | I2 | 1 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SB
2 - SB / T@SB
3 - SET$5715CE2E / V@SB
4 - SET$5715CE2E
5 - SEL$E32B9D82 / LXY@NB
6 - SEL$E32B9D82 / LXY@NB
7 - SEL$9113C594 / LXY_1@SEL$1
8 - SEL$9113C594 / LXY_1@SEL$1
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
INDEX_RS_ASC(@"SEL$E32B9D82" "LXY"@"NB" ("LXY"."OBJECT_ID"))
INDEX_RS_ASC(@"SEL$9113C594" "LXY_1"@"SEL$1" ("LXY_1"."OBJECT_ID"))
USE_NL(@"SB" "V"@"SB")
LEADING(@"SB" "T"@"SB" "V"@"SB")
NO_ACCESS(@"SB" "V"@"SB")
FULL(@"SB" "T"@"SB")
OUTLINE(@"SB")
OUTLINE(@"SET$1")
OUTLINE(@"SEL$1")
OUTLINE(@"NB")
OUTLINE_LEAF(@"SB")
PUSH_PRED(@"SB" "V"@"SB" 1)
OUTLINE_LEAF(@"SET$5715CE2E")
OUTLINE_LEAF(@"SEL$9113C594")
OUTLINE_LEAF(@"SEL$E32B9D82")
ALL_ROWS
DB_VERSION('11.2.0.4')
OPTIMIZER_FEATURES_ENABLE('11.2.0.4')
IGNORE_OPTIM_EMBEDDED_HINTS
END_OUTLINE_DATA
*/
Predicate Information (identified by operation id):
---------------------------------------------------
6 - access("LXY"."OBJECT_ID"="T"."A")
8 - access("LXY_1"."OBJECT_ID"="T"."A")
很明显,CBO对该sql做了视图合并,从10053可以看到更详细的信息
10053:
首先检查到可以对该视图做JPPD:***********************************
Cost-Based Join Predicate Push-down
***********************************
JPPD: Checking validity of push-down in query block SB (#1)
JPPD: Checking validity of push-down from query block SB (#1) to query block SET$1 (#2)
JPPD: Passed validity checks
JPPD: JPPD: Pushdown from query block SB (#1) passed validity checks.
Join-Predicate push-down on query block SB (#1)
JPPD: Using search type: linear
JPPD: Considering join predicate push-down
1)未做jppd的情况:
JPPD: Starting iteration 1, state space = (2) : (0)JPPD: Performing join predicate push-down (no transformation phase) from query block SB (#1) to query block SET$1 (#2)
...
JPPD: Updated best state, Cost = 106.38
验证一下不对sql做jppd的cost:
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20 | 2060 | 106 (0)| 00:00:02 |
|* 1 | HASH JOIN | | 20 | 2060 | 106 (0)| 00:00:02 |
| 2 | TABLE ACCESS FULL | T | 10 | 130 | 2 (0)| 00:00:01 |
| 3 | VIEW | | 28488 | 2503K| 104 (0)| 00:00:02 |
| 4 | UNION-ALL | | | | | |
| 5 | TABLE ACCESS FULL| LXY | 14243 | 431K| 52 (0)| 00:00:01 |
| 6 | TABLE ACCESS FULL| LXY_1 | 14245 | 431K| 52 (0)| 00:00:01 |
------------------------------------------------------------------------------
- select /*+ qb_name(sb) no_push_pred(v)*/t.a,v.object_name,v.object_type from t,(select /*+ qb_name(nb)*/* from lxy union all select * from lxy_1) v
- where t.a=v.object_id;
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20 | 2060 | 106 (0)| 00:00:02 |
|* 1 | HASH JOIN | | 20 | 2060 | 106 (0)| 00:00:02 |
| 2 | TABLE ACCESS FULL | T | 10 | 130 | 2 (0)| 00:00:01 |
| 3 | VIEW | | 28488 | 2503K| 104 (0)| 00:00:02 |
| 4 | UNION-ALL | | | | | |
| 5 | TABLE ACCESS FULL| LXY | 14243 | 431K| 52 (0)| 00:00:01 |
| 6 | TABLE ACCESS FULL| LXY_1 | 14245 | 431K| 52 (0)| 00:00:01 |
------------------------------------------------------------------------------
2)jppd转换后的情况
JPPD: Starting iteration 2, state space = (2) : (1)JPPD: Performing join predicate push-down (candidate phase) from query block SB (#1) to query block SET$1 (#2)
JPPD: Pushing predicate "T"."A"="V"."OBJECT_ID"
from query block SB (#1) to query block SET$1 (#2)
JPPD: Push dest of pred 0x8a74b4a8 is qb 0x8a74dff0:query block SET$1 (#2)
JPPD: Push dest of pred 0x8a4d3f98 is qb 0x8a74dff0:query block SET$1 (#2)
...
JPPD: Updated best state, Cost = 42.01
3)确定转换
JPPD: Will use JPPD from SB (#1) to SET$1 (#2). --由于转换后cost仅为42所以确定转换来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31347199/viewspace-2121619/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/31347199/viewspace-2121619/