Oracle Connect by和Hash join

时间:2016-01-06 13:50:38

标签: oracle oracle10g nested-loops hierarchical

我有一个查询1:

select *
from (
select 'null' parentcode, u.unititemcode childcode, null unititempartnbr, null partoid,
null proccode, null unititemtype, null qualcat, null unititemgm2, null rsncode
from wi_unititem u where
u.prodproccode='PM11' and
u.prodendtime>sysdate-10
union all
select p.unititemcode parentcode, u.unititemcode childcode, 0 unititempartnbr, p.oid partoid,
p.proccode, u.unititemtype, u.qualcat, u.unititemgm2, u.rsncode
from wi_uitempart p, wi_unititem u where
p.unititemparttype='USEDSET' and
u.prodproccode=p.proccode and
u.setid=p.setid    
) m
where m.unititemtype<>'SKID'
start with m.parentcode='null'
connect by prior m.childcode=m.parentcode

解释查询1的计划:

SELECT STATEMENT  ALL_ROWSCost: 64  Bytes: 2 745  Cardinality: 9                                    
23 FILTER                               
    22 CONNECT BY WITH FILTERING                            
        9 VIEW TIPSMSY. Cost: 12  Bytes: 610  Cardinality: 2                        
            8 UNION-ALL                     
                2 TABLE ACCESS BY INDEX ROWID TABLE TIPSMSY.WI_UNITITEM Cost: 4  Bytes: 29  Cardinality: 1                  
                    1 INDEX RANGE SCAN INDEX TIPSMSY.WI_UNITITEM_PROCCODE_ENDTIME Cost: 3  Cardinality: 1           
                7 TABLE ACCESS BY INDEX ROWID TABLE TIPSMSY.WI_UNITITEM Cost: 3  Bytes: 46  Cardinality: 1                  
                    6 NESTED LOOPS  Cost: 8  Bytes: 113  Cardinality: 1             
                        4 TABLE ACCESS BY INDEX ROWID TABLE TIPSMSY.WI_UITEMPART Cost: 5  Bytes: 67  Cardinality: 1         
                            3 INDEX RANGE SCAN INDEX (UNIQUE) TIPSMSY.WI_UITEMPART_PK Cost: 4  Cardinality: 1   
                        5 INDEX RANGE SCAN INDEX TIPSMSY.WI_UNITITEM_SETID Cost: 2  Cardinality: 1          
        21 VIEW TIPSMSY. Cost: 64  Bytes: 2 745  Cardinality: 9                         
            20 UNION-ALL                    
                12 FILTER               
                    11 TABLE ACCESS BY INDEX ROWID TABLE TIPSMSY.WI_UNITITEM Cost: 4  Bytes: 29  Cardinality: 1             
                        10 INDEX RANGE SCAN INDEX TIPSMSY.WI_UNITITEM_PROCCODE_ENDTIME Cost: 3  Cardinality: 1          
                19 TABLE ACCESS BY INDEX ROWID TABLE TIPSMSY.WI_UNITITEM Cost: 3  Bytes: 46  Cardinality: 1                 
                    18 NESTED LOOPS  Cost: 60  Bytes: 904  Cardinality: 8           
                        16 NESTED LOOPS         
                            13 CONNECT BY PUMP      
                            15 TABLE ACCESS BY INDEX ROWID TABLE TIPSMSY.WI_UITEMPART Cost: 18  Bytes: 938  Cardinality: 14     
                                14 INDEX RANGE SCAN INDEX (UNIQUE) TIPSMSY.WI_UITEMPART_PK Cost: 4  Cardinality: 43  
                        17 INDEX RANGE SCAN INDEX TIPSMSY.WI_UNITITEM_SETID Cost: 2  Cardinality: 1         

查询2:

select *
from (
select 'null' parentcode, u.unititemcode childcode, null unititempartnbr, null partoid,
null proccode, null unititemtype, null qualcat, null unititemgm2, null rsncode
from wi_unititem u where
u.prodproccode='PM11' and
u.prodendtime>sysdate-20
union all
select p.unititemcode parentcode, u.unititemcode childcode, 0 unititempartnbr, p.oid partoid,
p.proccode, u.unititemtype, u.qualcat, u.unititemgm2, u.rsncode
from wi_uitempart p, wi_unititem u where
p.unititemparttype='USEDSET' and
u.prodproccode=p.proccode and
u.setid=p.setid    
) m
where m.unititemtype<>'SKID'
start with m.parentcode='null'
connect by prior m.childcode=m.parentcode

解释查询2的计划:

SELECT STATEMENT  ALL_ROWSCost: 122  Bytes: 82 655  Cardinality: 271                                    
23 FILTER                               
    22 CONNECT BY WITH FILTERING                            
        9 VIEW TIPSMSY. Cost: 70  Bytes: 80 520  Cardinality: 264                       
            8 UNION-ALL                     
                2 TABLE ACCESS BY INDEX ROWID TABLE TIPSMSY.WI_UNITITEM Cost: 62  Bytes: 7 627  Cardinality: 263                
                    1 INDEX RANGE SCAN INDEX TIPSMSY.WI_UNITITEM_PROCCODE_ENDTIME Cost: 4  Cardinality: 263             
                7 TABLE ACCESS BY INDEX ROWID TABLE TIPSMSY.WI_UNITITEM Cost: 3  Bytes: 46  Cardinality: 1                  
                    6 NESTED LOOPS  Cost: 8  Bytes: 113  Cardinality: 1             
                        4 TABLE ACCESS BY INDEX ROWID TABLE TIPSMSY.WI_UITEMPART Cost: 5  Bytes: 67  Cardinality: 1         
                            3 INDEX RANGE SCAN INDEX (UNIQUE) TIPSMSY.WI_UITEMPART_PK Cost: 4  Cardinality: 1   
                        5 INDEX RANGE SCAN INDEX TIPSMSY.WI_UNITITEM_SETID Cost: 2  Cardinality: 1          
        21 VIEW TIPSMSY. Cost: 122  Bytes: 82 655  Cardinality: 271                         
            20 UNION-ALL                    
                12 FILTER               
                    11 TABLE ACCESS BY INDEX ROWID TABLE TIPSMSY.WI_UNITITEM Cost: 62  Bytes: 7 627  Cardinality: 263           
                        10 INDEX RANGE SCAN INDEX TIPSMSY.WI_UNITITEM_PROCCODE_ENDTIME Cost: 4  Cardinality: 263        
                19 TABLE ACCESS BY INDEX ROWID TABLE TIPSMSY.WI_UNITITEM Cost: 3  Bytes: 46  Cardinality: 1                 
                    18 NESTED LOOPS  Cost: 60  Bytes: 904  Cardinality: 8           
                        16 HASH JOIN        
                            13 CONNECT BY PUMP      
                            15 TABLE ACCESS BY INDEX ROWID TABLE TIPSMSY.WI_UITEMPART Cost: 18  Bytes: 938  Cardinality: 14     
                                14 INDEX FULL SCAN INDEX (UNIQUE) TIPSMSY.WI_UITEMPART_PK Cost: 4  Cardinality: 43  
                        17 INDEX RANGE SCAN INDEX TIPSMSY.WI_UNITITEM_SETID Cost: 2  Cardinality: 1         

查询1包含“sysdate-10”,查询2包含“sysdate-20”,这是唯一的区别,查询1运行速度非常快,查询2运行速度非常慢。

如果我们比较执行计划,那么差异可以在以14和16开头的行中找到: 查询1使用嵌套循环连接+索引范围扫描 查询2使用哈希加入+索引全扫描

是否可以将查询1的执行计划用于查询2?

1 个答案:

答案 0 :(得分:0)

复制执行计划的最简单方法是使用完整的大纲提示。

使用这两个语句生成包含大纲数据的解释计划。这也是生成解释计划的最佳方式,原因在我的回答here中描述了几个原因。

explain plan for select * from dual; --Add your real query here.
select * from table(dbms_xplan.display(format => '+outline'));

Plan hash value: 272002086

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |     2 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| DUAL |     1 |     2 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------

Outline Data
-------------

  /*+
      BEGIN_OUTLINE_DATA
      FULL(@"SEL$1" "DUAL"@"SEL$1")
      OUTLINE_LEAF(@"SEL$1")
      ALL_ROWS
      DB_VERSION('12.1.0.2')
      OPTIMIZER_FEATURES_ENABLE('12.1.0.2')
      IGNORE_OPTIM_EMBEDDED_HINTS
      END_OUTLINE_DATA
  */

使用大纲数据作为提示,以保证执行计划保持不变。虽然&#34;保证&#34;可能是一个强有力的词;这些未记录的提示可能无法在不同的版本中工作,或者如果查询在语义上不同。

select 
  /*+
      BEGIN_OUTLINE_DATA
      FULL(@"SEL$1" "DUAL"@"SEL$1")
      OUTLINE_LEAF(@"SEL$1")
      ALL_ROWS
      DB_VERSION('12.1.0.2')
      OPTIMIZER_FEATURES_ENABLE('12.1.0.2')
      IGNORE_OPTIM_EMBEDDED_HINTS
      END_OUTLINE_DATA
  */
* from dual;

这应该有效,但有点难看。理想情况下,您想了解Oracle为什么做出错误决定的根本原因 - 调查估计与实际的基数,统计数据等。但是有很多方法可以做到这一点并且需要很长时间。作为折衷方案,您可能希望使用提示并尝试将其缩小到仅修复性能问题所需的一两个。