zoukankan      html  css  js  c++  java
  • oracle sql 执行计划分析

    转自http://itindex.net/detail/45962-oracle-sql-%E8%AE%A1%E5%88%92

    一、首先创建表

    1. SQL> show user
    2. USER is "RHYS"
    3. SQL> create table A(col1 number(4,0),col2 number(4,0), col4 char(30));
    4. create table B(col1 number(4,0),col3 number(4,0), name_b char(30));
    5. create table C(col2 number(4,0),col3 number(4,0), name_c char(30));
    6. Table created.
    7. SQL>
    8. Table created.
    9. SQL>
    10. Table created.

    第二、查看一下执行计划。
    1、

    1. SQL> select a.col4 from c,a,b
    2. 2 where c.col3=5 and a.col1=b.col1 and a.col2=c.col2 and b.col3=10;
    3. Execution Plan
    4. ----------------------------------------------------------
    5. Plan hash value: 1485247927
    6. ------------------------------------------------------------------------------
    7. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    8. ------------------------------------------------------------------------------
    9. | 0 | SELECT STATEMENT | | 1 | 110 | 6 (0)| 00:00:01 |
    10. |* 1 | HASH JOIN | | 1 | 110 | 6 (0)| 00:00:01 |
    11. | 2 | MERGE JOIN CARTESIAN| | 1 | 52 | 4 (0)| 00:00:01 |
    12. |* 3 | TABLE ACCESS FULL | C | 1 | 26 | 2 (0)| 00:00:01 |
    13. | 4 | BUFFER SORT | | 1 | 26 | 2 (0)| 00:00:01 |
    14. |* 5 | TABLE ACCESS FULL | B | 1 | 26 | 2 (0)| 00:00:01 |
    15. | 6 | TABLE ACCESS FULL | A | 1 | 58 | 2 (0)| 00:00:01 |
    16. ------------------------------------------------------------------------------
    17. Predicate Information (identified by operation id):
    18. ---------------------------------------------------
    19. 1 - access("A"."COL1"="B"."COL1" AND "A"."COL2"="C"."COL2")
    20. 3 - filter("C"."COL3"=5)
    21. 5 - filter("B"."COL3"=10)
    22. Note
    23. -----
    24. - dynamic sampling used for this statement (level=2)

    执行计划主要查看:访问路径,连接顺序,连接方法
    执行计划顺序为上内原则,同层次上边先执行,内层先执行。
    plan hash value:当sql第一次在shared pool中进行执行的是硬解析并生产该hash值
    id,只是一个标号,并不是实际执行顺序
    operation:从字面意思也看出来就是操作的类型
    name:对象的名字
    rows:oracle估计该操作返回的行数
    bytes:产生的数据量
    cost:表示该sql执行 到此步骤的时候sql执行代价。
    该sql的执行步骤如下:
    首先执行id 3-》id5-》id4—》id2-》id6-》id1-》id0
    首先对id3进行全表扫描过滤条件为filter("C"."COL3"=5),然后对表b进行全表扫描,条件为 filter("B"."COL3"=10),完了之后再进行buffer sort排序,最后把3和4的row source 进行merge join 笛卡尔积操作,并把所有的结果作为row source1 ,也就是驱动表,然后把表A作为被探测表,两者进行hash join。这就是这一个过程信息。
    注意此处在id5和id3没有关联的条件,就采用了笛卡尔积,这是不好的现象。
    2、

    1. SQL> select /*+ordered*/ a.col4 from c,a,b
    2. 2 where c.col3=5 and a.col1=b.col1 and a.col2=c.col2 and b.col3=10;
    3. Execution Plan
    4. ----------------------------------------------------------
    5. Plan hash value: 531790806
    6. ----------------------------------------------------------------------------
    7. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    8. ----------------------------------------------------------------------------
    9. | 0 | SELECT STATEMENT | | 1 | 110 | 6 (0)| 00:00:01 |
    10. |* 1 | HASH JOIN | | 1 | 110 | 6 (0)| 00:00:01 |
    11. |* 2 | HASH JOIN | | 1 | 84 | 4 (0)| 00:00:01 |
    12. |* 3 | TABLE ACCESS FULL| C | 1 | 26 | 2 (0)| 00:00:01 |
    13. | 4 | TABLE ACCESS FULL| A | 1 | 58 | 2 (0)| 00:00:01 |
    14. |* 5 | TABLE ACCESS FULL | B | 1 | 26 | 2 (0)| 00:00:01 |
    15. ----------------------------------------------------------------------------
    16. Predicate Information (identified by operation id):
    17. ---------------------------------------------------
    18. 1 - access("A"."COL1"="B"."COL1")
    19. 2 - access("A"."COL2"="C"."COL2")
    20. 3 - filter("C"."COL3"=5)
    21. 5 - filter("B"."COL3"=10)
    22. Note
    23. -----
    24. - dynamic sampling used for this statement (level=2)

    使用hints可以调整optimizer的执行连接方法,在此例中我们指定了ordered使得采用hash join选取from 之后从左到有第一个表c作为驱动表。
    执行顺序为:id3全表扫描过滤条件为filter("C"."COL3"=5)-》id4 全表扫描,然后表c为驱动表,a为探测表以此来进行hashjoin-》id5 全表扫描过滤条件为filter("B"."COL3"=10),此后执行id2为外部表,id5为被探测表进行hash join,从access访问路径可以看出首先是id2为("A"."COL2"="C"."COL2")此后为 id1access("A"."COL1"="B"."COL1")。
    这是整个sql执行的整个过程。
    为了便于理解分析一下数据,
    首先我要取到在表c中col3=5的所有数据,然后再内存进行hash,作为hash table,然后我在去使用该hash table去探测A表进行匹配,取出的数据为access("A"."COL2"="C"."COL2"),把最后的匹配结果作为row source,再次建立hash table表,然后再去探测b表,方式为:access("A"."COL1"="B"."COL1")。最终获得了0执行的结果信息。
    对于note动态采样信息请参考:
    http://www.oracle.com/technetwork/issue-archive/2009/09-jan/o19asktom-086775.html
    由于本次没有对表进行analyze所有存有动态取样。

    1. SQL> select /*+ordered use_nl(a c)*/ a.col4 from c,a,b
    2. 2 where c.col3=5 and a.col1=b.col1 and a.col2=c.col2 and b.col3=10;
    3. Execution Plan
    4. ----------------------------------------------------------
    5. Plan hash value: 1446226736
    6. ----------------------------------------------------------------------------
    7. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    8. ----------------------------------------------------------------------------
    9. | 0 | SELECT STATEMENT | | 1 | 110 | 6 (0)| 00:00:01 |
    10. |* 1 | HASH JOIN | | 1 | 110 | 6 (0)| 00:00:01 |
    11. | 2 | NESTED LOOPS | | 1 | 84 | 4 (0)| 00:00:01 |
    12. |* 3 | TABLE ACCESS FULL| C | 1 | 26 | 2 (0)| 00:00:01 |
    13. |* 4 | TABLE ACCESS FULL| A | 1 | 58 | 2 (0)| 00:00:01 |
    14. |* 5 | TABLE ACCESS FULL | B | 1 | 26 | 2 (0)| 00:00:01 |
    15. ----------------------------------------------------------------------------
    16. Predicate Information (identified by operation id):
    17. ---------------------------------------------------
    18. 1 - access("A"."COL1"="B"."COL1")
    19. 3 - filter("C"."COL3"=5)
    20. 4 - filter("A"."COL2"="C"."COL2")
    21. 5 - filter("B"."COL3"=10)
    22. Note
    23. -----
    24. - dynamic sampling used for this statement (level=2)

    在这个语句中,表c和a进行了nested loops然后把结果惊醒hash table在与表b做jash join。

    另外对于表有索引的情况进行如下分析。
    首先创建表a的组合索引,索引列为(col1,col2)
    eg:

    1. SQL> create index inx_col12A on a(col1,col2);
    2. Index created.
    3. SQL> select A.col4
    4. 2 from C , A , B
    5. 3 where C.col3 = 5 and A.col1 = B.col1 and A.col2 = C.col2
    6. 4 and B.col3 = 10;
    7. Execution Plan
    8. ----------------------------------------------------------
    9. Plan hash value: 2122808611
    10. -------------------------------------------------------------------------------------------
    11. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    12. -------------------------------------------------------------------------------------------
    13. | 0 | SELECT STATEMENT | | 1 | 110 | 4 (0)| 00:00:01 |
    14. | 1 | NESTED LOOPS | | 1 | 110 | 4 (0)| 00:00:01 |
    15. | 2 | NESTED LOOPS | | 1 | 110 | 4 (0)| 00:00:01 |
    16. | 3 | MERGE JOIN CARTESIAN | | 1 | 52 | 4 (0)| 00:00:01 |
    17. |* 4 | TABLE ACCESS FULL | C | 1 | 26 | 2 (0)| 00:00:01 |
    18. | 5 | BUFFER SORT | | 1 | 26 | 2 (0)| 00:00:01 |
    19. |* 6 | TABLE ACCESS FULL | B | 1 | 26 | 2 (0)| 00:00:01 |
    20. |* 7 | INDEX RANGE SCAN | INX_COL12A | 1 | | 0 (0)| 00:00:01 |
    21. | 8 | TABLE ACCESS BY INDEX ROWID| A | 1 | 58 | 0 (0)| 00:00:01 |
    22. -------------------------------------------------------------------------------------------
    23. Predicate Information (identified by operation id):
    24. ---------------------------------------------------
    25. 4 - filter("C"."COL3"=5)
    26. 6 - filter("B"."COL3"=10)
    27. 7 - access("A"."COL1"="B"."COL1" AND "A"."COL2"="C"."COL2")
    28. Note
    29. -----
    30. - dynamic sampling used for this statement (level=2)

    这个比较有意思了。首先看一下执行顺序,首先对表c进行全表扫描过滤条件为col3=5取出数据作为row source1,然后再对b进行全表扫描过滤条件为col3=10,因为走的是merge join 笛卡尔积的排序连接,然后再buffer 进行sort作为row sources2 ,完了之后row source1和row source2作合并连接,完了之后作为row source1 是驱动表,然后再进行index range scan(索引范围扫描)访问路径为: access("A"."COL1"="B"."COL1" AND "A"."COL2"="C"."COL2"),完了之后把结果作为row source1 然后再去与表A进行嵌套循环操作,不过A也就是id8 走的是index rowid。完了之后再进行0获得数据。太繁琐了。呵呵。

    1. SQL> select /*+ ORDERED USE_NL (A C)*/ A.col4
    2. 2 from C , A , B
    3. 3 where C.col3 = 5 and A.col1 = B.col1 and A.col2 = C.col2
    4. 4 and B.col3 = 10;
    5. Execution Plan
    6. ----------------------------------------------------------
    7. Plan hash value: 1446226736
    8. ----------------------------------------------------------------------------
    9. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    10. ----------------------------------------------------------------------------
    11. | 0 | SELECT STATEMENT | | 1 | 110 | 6 (0)| 00:00:01 |
    12. |* 1 | HASH JOIN | | 1 | 110 | 6 (0)| 00:00:01 |
    13. | 2 | NESTED LOOPS | | 1 | 84 | 4 (0)| 00:00:01 |
    14. |* 3 | TABLE ACCESS FULL| C | 1 | 26 | 2 (0)| 00:00:01 |
    15. |* 4 | TABLE ACCESS FULL| A | 1 | 58 | 2 (0)| 00:00:01 |
    16. |* 5 | TABLE ACCESS FULL | B | 1 | 26 | 2 (0)| 00:00:01 |
    17. ----------------------------------------------------------------------------
    18. Predicate Information (identified by operation id):
    19. ---------------------------------------------------
    20. 1 - access("A"."COL1"="B"."COL1")
    21. 3 - filter("C"."COL3"=5)
    22. 4 - filter("A"."COL2"="C"."COL2")
    23. 5 - filter("B"."COL3"=10)
    24. Note
    25. -----
    26. - dynamic sampling used for this statement (level=2)

    当改变optimizer选择的执行计划时候,添加了hints,然后我们使用嵌套循环,驱动表为c,被驱动表为A,完了之后再作为row source1做为hash table, 然后与表B进行hash join。

    1. SQL> select /*+ USE_NL (A C)*/ A.col4
    2. 2 from C , A , B
    3. 3 where C.col3 = 5 and A.col1 = B.col1 and A.col2 = C.col2
    4. 4 and B.col3 = 10;
    5. Execution Plan
    6. ----------------------------------------------------------
    7. Plan hash value: 2122808611
    8. -------------------------------------------------------------------------------------------
    9. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    10. -------------------------------------------------------------------------------------------
    11. | 0 | SELECT STATEMENT | | 1 | 110 | 4 (0)| 00:00:01 |
    12. | 1 | NESTED LOOPS | | 1 | 110 | 4 (0)| 00:00:01 |
    13. | 2 | NESTED LOOPS | | 1 | 110 | 4 (0)| 00:00:01 |
    14. | 3 | MERGE JOIN CARTESIAN | | 1 | 52 | 4 (0)| 00:00:01 |
    15. |* 4 | TABLE ACCESS FULL | C | 1 | 26 | 2 (0)| 00:00:01 |
    16. | 5 | BUFFER SORT | | 1 | 26 | 2 (0)| 00:00:01 |
    17. |* 6 | TABLE ACCESS FULL | B | 1 | 26 | 2 (0)| 00:00:01 |
    18. |* 7 | INDEX RANGE SCAN | INX_COL12A | 1 | | 0 (0)| 00:00:01 |
    19. | 8 | TABLE ACCESS BY INDEX ROWID| A | 1 | 58 | 0 (0)| 00:00:01 |
    20. -------------------------------------------------------------------------------------------
    21. Predicate Information (identified by operation id):
    22. ---------------------------------------------------
    23. 4 - filter("C"."COL3"=5)
    24. 6 - filter("B"."COL3"=10)
    25. 7 - access("A"."COL1"="B"."COL1" AND "A"."COL2"="C"."COL2")
    26. Note
    27. -----
    28. - dynamic sampling used for this statement (level=2)
    29. SQL>

    注意当我们对表进行了分析之后,那么就不会有动态分析了,动态分析只是为了进行执行计划的选择。
    对于分析表知识详解:
    http://blog.csdn.net/xiaohai20102010/article/details/8777158

    1. <pre>SQL> set autotrace off
    2. SQL> analyze table a compute statistics;
    3. Table analyzed.
    4. SQL> analyze table b compute statistics;
    5. Table analyzed.
    6. SQL> analyze table c compute statistics;
    7. Table analyzed.
    8. SQL> analyze index inx_col12A compute statistics;
    9. Index analyzed.
    10. SQL> select A.col4
    11. 2 from C , A , B
    12. 3 where C.col3 = 5 and A.col1 = B.col1 and A.col2 = C.col2
    13. 4 and B.col3 = 10;
    14. no rows selected
    15. SQL> set auotrace trace explain
    16. SP2-0158: unknown SET option "auotrace"
    17. SQL> set autotrace trace explain
    18. SQL> r
    19. 1 select A.col4
    20. 2 from C , A , B
    21. 3 where C.col3 = 5 and A.col1 = B.col1 and A.col2 = C.col2
    22. 4* and B.col3 = 10
    23. Execution Plan
    24. ----------------------------------------------------------
    25. Plan hash value: 2122808611
    26. -------------------------------------------------------------------------------------------
    27. | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    28. -------------------------------------------------------------------------------------------
    29. | 0 | SELECT STATEMENT | | 1 | 110 | 4 (0)| 00:00:01 |
    30. | 1 | NESTED LOOPS | | 1 | 110 | 4 (0)| 00:00:01 |
    31. | 2 | NESTED LOOPS | | 1 | 110 | 4 (0)| 00:00:01 |
    32. | 3 | MERGE JOIN CARTESIAN | | 1 | 52 | 4 (0)| 00:00:01 |
    33. |* 4 | TABLE ACCESS FULL | C | 1 | 26 | 2 (0)| 00:00:01 |
    34. | 5 | BUFFER SORT | | 1 | 26 | 2 (0)| 00:00:01 |
    35. |* 6 | TABLE ACCESS FULL | B | 1 | 26 | 2 (0)| 00:00:01 |
    36. |* 7 | INDEX RANGE SCAN | INX_COL12A | 1 | | 0 (0)| 00:00:01 |
    37. | 8 | TABLE ACCESS BY INDEX ROWID| A | 1 | 58 | 0 (0)| 00:00:01 |
    38. -------------------------------------------------------------------------------------------
    39. Predicate Information (identified by operation id):
    40. ---------------------------------------------------
    41. 4 - filter("C"."COL3"=5)
    42. 6 - filter("B"."COL3"=10)
    43. 7 - access("A"."COL1"="B"."COL1" AND "A"."COL2"="C"."COL2")
    44. </pre>




  • 相关阅读:
    Spring--自定义注解
    IntelliJ IDEA实用插件
    Zero date value prohibited解决方法
    如何保证幂等性
    Map遍历的几种方式
    Static关键字
    索引失效 -- 使用Between范围查询时
    接口的不同写法在Swagger上的不同
    js与jquery获取input输入框中的值
    一个简单的 aiax请求例子
  • 原文地址:https://www.cnblogs.com/haoxiaoyu/p/6e6d5e7158f3ea611d78b109d6436912.html
Copyright © 2011-2022 走看看