oracle sql 执行计划分析

时间:2022-08-23 19:30:29

转自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>

oracle sql 执行计划分析的更多相关文章

  1. Oracle sql执行计划解析

    Oracle sql执行计划解析 https://blog.csdn.net/xybelieve1990/article/details/50562963 Oracle优化器 Oracle的优化器共有 ...

  2. 查看Oracle SQL执行计划的常用方式

    在查看SQL执行计划的时候有很多方式 我常用的方式有三种 SQL> explain plan for 2 select * from scott.emp where ename='KING'; ...

  3. 分析 Oracle SQL 执行计划的关注点

    本文内容摘自<剑破冰山--Oracle开发艺术>一书. 1.判定主要矛盾 在遇到复杂 SQL 语句时,执行计划也非常复杂,往往让人分析起来觉得无从下手,此时应避免顺序解决问题,而是快速定位 ...

  4. &lbrack;转&rsqb; 多种方法查看Oracle SQL执行计划

    本文转自:http://falchion.iteye.com/blog/616234 一.在线查看执行计划表 如果PLAN_TABLE表不存在,执行$ORACLE_HOME/rdbms/admin/u ...

  5. SQL执行计划分析

    explain执行计划中的字段以及含义在下面的博客中有详细讲述: https://blog.csdn.net/da_guo_li/article/details/79008016 执行计划能告诉我们什 ...

  6. Oracle sql执行计划

    explain plan     explain plan for sql_statement     select * from table(dbms_xplan.display) DBMS_XPL ...

  7. SQL执行计划分析2

    执行计划重点关注 type.key.key_len.rows.extra type:type如果为ALL,表示全盘扫描,也是效率最低的 key:表示使用了哪个索引,如果没有使用为null key_le ...

  8. Oracle查看SQL执行计划的方式

    Oracle查看SQL执行计划的方式     获取Oracle sql执行计划并查看执行计划,是掌握和判断数据库性能的基本技巧.下面案例介绍了多种查看sql执行计划的方式:   基本有以下几种方式: ...

  9. sql执行计划变更和删除缓存中执行计划的方法

    将指定SQL的执行计划从共享池删除的方法 http://www.2cto.com/database/201204/126388.html Oracle SQL执行计划变更的问题 http://www. ...

随机推荐

  1. Duilib源码分析&lpar;四&rpar;绘制管理器—CPaintManagerUI—&lpar;前期准备二&rpar;

    接下来,我们继续分析UIlib.h文件中余下的文件,当然部分文件可能顺序错开分析,这样便于从简单到复杂的整个过程的里面,而避免一开始就出现各种不理解的地方. 1. UIManager.h:UI管理器, ...

  2. double 逆序

    请设计一个函数,不许用到字符串函数,用数学运算,将double类型数据转换,例如123.456转换成654.321 int _tmain(int argc, _TCHAR* argv[]) { con ...

  3. NSDateFormatter 根据时间戳求出时间

    NSDateFormatter 根据时间戳求出时间 - (void)detailWithStyle:(NSString*)style time:(NSInteger)time { // NSStrin ...

  4. PostgreSQL&colon; Query for location of global tablespace&quest;

    Q: I have been trying to make our database clients pro-active about not filling up the partition on ...

  5. order by多个字段对索引的影响

    某前台sql语句,简化后如下SELECT products_name,products_viewed FROM `products_description` ORDER BY products_vie ...

  6. JAVA--可变长参数

    可变长参数: 可变长参数可以接受任意个数的实参,形参实际上是一个数组. 语法形式: 方法名称(类型 参数1,类型 参数2,类型...可变长参数) *可变长参数一定是方法的最后一个参数 public v ...

  7. css3实现聊天气泡

    1: <div class="comment"></div><style type="text/css"> .comment ...

  8. AT3611 Tree MST 点分治&plus;最小生成树

    正解:点分治+最小生成树 解题报告: 传送门! 然后这题麻油翻译,,,所以这边的建议是先说下题意呢亲 所以题意大概就是说,给一棵n个节点的树,树上每个点都有个权值,然后构造一个完全图,(u,v)之间连 ...

  9. 实训三(cocos2dx 3&period;x 打包apk)

    上一篇文章<实训二(cocos2dx 2.x 打包apk)>简单的讲述的利用cocos2dx 2.x引擎在windows平台上打包apk的方法与过程,本文将介绍3.x版本引擎,如何打包ap ...

  10. ubuntu14&period;04如何设置静态IP的方法

    第一步: 配置静态IP地址: 打开/etc/network/interfaces文件,内容为 auto lo iface lo inet loopback auto eth0 iface eth0 i ...