SELECT a.empno 
FROM dept b, emp a, salgrade c 
WHERE EXISTS (SELECT a.empno 
              FROM dept b, emp a, salgrade c 
              WHERE a.deptno=b.deptno 
              AND a.job <> 'CLERK' 
              AND a.sal BETWEEN c.losal AND c.hisal) 
AND a.deptno=b.deptno 
AND a.job <> 'CLERK' 
AND a.sal between losal and hisal; 
 
OPTIMIZER_GOAL is set to RULE. 
 
 
Query Without Hints 
=================== 
 
The execution path for this query without the use of any hints...: 
 
Execution Plan 
---------------------------------------------------------- 
   0      SELECT STATEMENT Optimizer=RULE 
   1    0   FILTER 
   2    1     MERGE JOIN 
   3    2       SORT (JOIN) 
   4    3         NESTED LOOPS 
   5    4           TABLE ACCESS (FULL) OF 'SALGRADE' 
   6    4           TABLE ACCESS (FULL) OF 'EMP' 
   7    2       SORT (JOIN) 
   8    7         TABLE ACCESS (FULL) OF 'DEPT' 
   9    1     MERGE JOIN 
  10    9       SORT (JOIN) 
  11   10         NESTED LOOPS 
  12   11           TABLE ACCESS (FULL) OF 'SALGRADE' 
  13   11           TABLE ACCESS (FULL) OF 'EMP' 
  14    9       SORT (JOIN) 
  15   14         TABLE ACCESS (FULL) OF 'DEPT' 
----------------------------------------
我的问题是
1,在上述执行计划中怎么可以看出哪个表是driving table ,哪个是proble table;
2,另外哪几个步骤是外部查询的执行计划,哪几个步骤是内部查询的执行计划?

解决方案 »

  1.   

    一般你不指定基础表,默认是最右边的,在你的sql里,就是salgrade表
    你的执行计划里好多全表扫描噢
    都不做索引的啊?
      

  2.   

    没做索引,这个不是实际数据。我就是没看懂在执行计划中驱动表在哪个位置
    ,还有就是根据执行计划怎么能看出oracle的实际执行步骤。按照楼上的说法,salgrade是驱动表
    我有点没想通,按照下面的连接条件a.sal between c.losal and c.hisal 
    使用c作为驱动好像不太合适吧?
    oracle怎么能根据c表的losal和hisal去连接a表呢?
      

  3.   

    我有点想当然,觉得既然连接条件是a.sal between c.losal and c.hisal 
    那么是不是应该以a表做驱动去遍历查询c表比较合适一些?
      

  4.   

    oracle默认规则,以from 之后最右边的表做为基础表,其它表与基础表进行关联比较
    所以一般会把数据量最小的表放在最右边,如果是交叉表,就把交叉表放在最后
    不过你以手动指定基础表的
      

  5.   

    在optimizer_mode = rule的情况下,
    驱动表的判断确实如此。
    如果在optimizer_mode不是rule那就另当别论了。
      

  6.   

    YES
    你可以用HINT来指定基础表
      

  7.   

     9    1     MERGE JOIN 
      10    9       SORT (JOIN) 
      11   10         NESTED LOOPS 
      12   11           TABLE ACCESS (FULL) OF 'SALGRADE' 
      13   11           TABLE ACCESS (FULL) OF 'EMP' 
      14    9       SORT (JOIN) 
      15   14         TABLE ACCESS (FULL) OF 'DEPT'  
    --------------------------
    it is very clear in plan.
    step 1: dept full scan
    step 2: sort
    step 3: salgrade full scan
    step 4: emp full scan
    step 5: Nest loop from step3 and step4
    step 6: sort
    step 7: Merge join from step2 and step6
    ...
      

  8.   

    little mistake
    step 1: dept full scan
    step 2: sort
    step 3: emp full scan
    step 4: salgrade full scan
    step 5: Nest loop from step3 and step4
    step 6: sort
    step 7: Merge join from step2 and step6 
    ...
      

  9.   

    9    1     MERGE JOIN  
      10    9       SORT (JOIN)  
      11   10         NESTED LOOPS  
      12   11           TABLE ACCESS (FULL) OF 'SALGRADE'  
      13   11           TABLE ACCESS (FULL) OF 'EMP'  
      14    9       SORT (JOIN)  
      15   14         TABLE ACCESS (FULL) OF 'DEPT'   
    -------------------------- 
    step 1: dept full scan 
    step 2: sort 
    step 3: emp full scan 
    step 4: salgrade full scan 
    step 5: Nest loop from step3 and step4 
    step 6: sort 
    step 7: Merge join from step2 and step6  
    -----------------------------------------------------------
    如果我没理解错的话,cenlmmx 的意思是不是说在执行计划中靠下的表为驱动表?
      

  10.   

    执行顺序我能看出来,现在的疑惑在于下面的嵌套循环中哪个表在前面,哪个在后面?
               NESTED LOOPS  
      12   11           TABLE ACCESS (FULL) OF 'SALGRADE'  
      13   11           TABLE ACCESS (FULL) OF 'EMP'  
      

  11.   

    根据前面两列的数字特点,我感觉这个执行计划有点类似一颗执行树,而这个树的执行顺序应该从叶子节点开始。
    按照这个原则,下面执行计划的步骤应该跟cenlmmx 的说法有点出入
    9    1     MERGE JOIN   
      10    9       SORT (JOIN)   
      11   10         NESTED LOOPS   
      12   11           TABLE ACCESS (FULL) OF 'SALGRADE'   
      13   11           TABLE ACCESS (FULL) OF 'EMP'   
      14    9       SORT (JOIN)   
      15   14         TABLE ACCESS (FULL) OF 'DEPT'    
    --------------------------  
    step 1: salgrade full scan  
    step 2: emp full scan
    step 3: Nest loop from step1 and step2 
    step 4: sort  
    step 5: dept full scan  
    step 6: sort  
    step 7: Merge join from step4 and step6  
    ---------------------------------------
    不知道我理解的对不对,
    按照我这种理解方式,驱动表应该是在执行计划中靠上面的数据源,也就是在执行计划树中靠左面的节点。
    这种方式比较容易让人理解和接收。
    从后到前的话,就是说用树的右节点作为驱动节点,好像跟习惯不符 
      

  12.   

    如果我没理解错的话,cenlmmx 的意思是不是说在执行计划中靠下的表为驱动表?
    -------------------------------
    yes,driving table is the table which is scanned firstly in plan.现在的疑惑在于下面的嵌套循环中哪个表在前面,哪个在后面?
               NESTED LOOPS  
      12   11           TABLE ACCESS (FULL) OF 'SALGRADE'  
      13   11           TABLE ACCESS (FULL) OF 'EMP'   
    ---------------------------
    of course, emp first,salgrade is second.As I am working on server now, so only write EN, sorry.
      

  13.   

    to cenlmmx :非常感谢您热心参与。
    我看到两篇观点一致的资料,其执行顺序都跟您在这里描述的有所偏差。总结两个资料的共同点和您的观点,
    共同点在于oracle会根据左面两列的序号建立执行计划树,然后按照后序遍历的方法执行,就是先左子节点,后右子节点,最后是根节点。而现在的矛盾点在树中左子节点和右子节点在执行计划中的位置。
    我看到的两篇资料中认为在执行计划中序号靠前的为子节点,根据这种观点建立的计划树应该是:
    9    1     MERGE JOIN   
      10    9       SORT (JOIN)   
      11   10         NESTED LOOPS   
      12   11           TABLE ACCESS (FULL) OF 'SALGRADE'   
      13   11           TABLE ACCESS (FULL) OF 'EMP'   
      14    9       SORT (JOIN)   
      15   14         TABLE ACCESS (FULL) OF 'DEPT'                                1
                                  9
               10                               14
               11
    12               13                            15
    这样执行起来步骤就是12,13,11,10,15,14,9,1而您的观点好像是直接将执行计划顺时针旋转90度得到执行树,这样的话建立的树应该是
                                     1
                                 9
            14                                      10
            15                                      11
                                           13                12
    这时执行的步骤应该是15,14,13,12,11,10,9,1
      

  14.   

    to cenlmmx:首先感谢关注
    刚查过两篇观点相似的资料,根你在这里描述的说法有一致但也有偏差。首先,观点统一的部分应该是oracle会按照执行计划中左面两列建立一个执行树,然后对执行树执行后序遍历以执行树中的步骤,观点差异在于树建立的时候子节点在执行计划中的位置。
    -----------------------------------
    针对这里描述的执行计划:
    9    1     MERGE JOIN    
      10    9       SORT (JOIN)    
      11   10         NESTED LOOPS    
      12   11           TABLE ACCESS (FULL) OF 'SALGRADE'    
      13   11           TABLE ACCESS (FULL) OF 'EMP'    
      14    9       SORT (JOIN)    
      15   14         TABLE ACCESS (FULL) OF 'DEPT'     
    cenlmmx的观点认为树应该是直接将执行计划顺时针旋转90度得到,这样建立的执行计划树应该是
                    1
                  9
        14                10
        15                11
                        13   12
    后序遍历上面的树得到的执行顺序应该是  15,14,13,12,11,10,19,1
    ----------------------------------------------
    另外一种观点是按照步骤在执行计划中出现的顺序确定其在执行计划中的位置,先出现的为左子节点,这样建立的计划树应该是
                    1
                  9
        10              14
        11              15
       12  13
    后序遍历上面的树得到的执行顺序应该是 12,13,11,10,15,14,9,1
      

  15.   

    这有什么好说的,缩进越多就是越先开始的步骤,如果还不明了,可以在pl/sql developer plan窗口看,在那里你可以从第一步骤浏览到最后一个步骤,否则缩进还有什么意义?
    其次驱动表,在oracle高版本已经不怎么提倡了,因为在高版本下,优化模式和以前版本有很大区别,只要按照执行计划再结合实际语句你就知道sql语句是如何执行的了。
      

  16.   

    看了下,应该还是以SALGRADE为基础表(应该就是你们说的驱动表)
    我对执行计划还停留的初步的,看是否有全表扫描之类的
    对怎么看执行计划的执行顺序还不太了解,看了上面星星的解释,学了不少