如何获取真实的执行计划 (上)

在ORACLE中,一条SQL的执行计划可以帮助我们了解该SQL的运行步骤,从而判断相应的执行计划是否合理,其瓶颈在何处等。所以,执行计划是我们调整SQL的一个重要参考。
在说明如何获取真实的执行计划前,我们先看一下通常获取执行计划的几种方法:
1、explain for ... 
2、set autotrace on
3、 dbms_xplan.display_cursor
4、 10046 trace跟踪
5、 awrsqrpt.sql

在进行具体的演示前,我们均以下面的SQL做为样例。
  SELECT  *

FROM t1, t2

WHERE t1.id = t2.t1_id

AND t1.n in(18,19);

 

其中,t1表有记录1000行,t2表有记录100000万;在T1表的n列和T2表的T1_id列上建有索引。

 

  方法1:explain plan for

SQL> explain plan for

    SELECT  *

FROM t1, t2

WHERE t1.id = t2.t1_id

AND t1.n in(18,19);  

 

Explained.

 

SQL> select * from table(dbms_xplan.display());

Plan hash value: 128660979

 

-------------------------------------------------------------------------------------------

| Id  | Operation                    | Name         | Rows  | Bytes | Cost (%CPU)| Time          |

-------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT          |   |   2 |  8138 |      8   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID   | T2          |   1 |  2041 |      2   (0)| 00:00:01 |

|   2 |   NESTED LOOPS                       |   |   2 |  8138 |      8   (0)| 00:00:01 |

|   3 |    INLIST ITERATOR        |   |     |     |          |   |

|   4 |     TABLE ACCESS BY INDEX ROWID| T1          |   2 |  4056 |      4   (0)| 00:00:01 |

|*  5 |      INDEX RANGE SCAN               | T1_N          |   4 |      |   2   (0)| 00:00:01 |

|*  6 |    INDEX RANGE SCAN           | T2_T1_ID |      1 |      |   1   (0)| 00:00:01 |

-------------------------------------------------------------------------------------------

 

Predicate Information (identified by operation id):

---------------------------------------------------

 

   5 - access("T1"."N"=18 OR "T1"."N"=19)

   6 - access("T1"."ID"="T2"."T1_ID")

 

Note

-----

   - dynamic sampling used for this statement

 

23 rows selected.

特点:1、不会真正执行SQL语句。故,执行计划结果返回快,无SQL语句的执行结果输出,返回的执行计划可能不是真正的执行计划。

         2、无统计信息

注:在一些图形化开发和管理集成工具中(比如PL/SQL DEVELOPER)查看执行计划,其实质就是使用explain for的方法。

     

 

     方法2: set autotrace on;

SQL> set autotrace on

SQL> set pagesize 2000;

SQL> SELECT  *

FROM t1, t2

WHERE t1.id = t2.t1_id

AND t1.n in(18,19);  2    3    4 

 

         ID         N

---------- ----------

CONTENTS

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


-------------------------------------------------------------------------------------------------------------------------------------------------------------------

         ID     T1_ID              N

---------- ---------- ----------

CONTENTS

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


-------------------------------------------------------------------------------------------------------------------------------------------------------------------

         18        18

yFfYpcNtsxEpvWUOceJmHtvpCEbcJTUTeKExdHlGlwoIFEgmOo

         18        18             18

OWCPIKKFQTMBZAVJBUGPOGOZGPHCMTGFDJTMCIZXRFVXYCATTY

 

         19        19

jAOYAJHBzwhNWHImZeFUOaxvMycbQsCLKhsUnSFwZpyctEahjK

         19        19             19

BEQUUMJSUDRLTCGOCIUHSZCNNJOTZOCEQKBZPSLHGAKRTLJAHX

 

 

 

Execution Plan

----------------------------------------------------------

Plan hash value: 128660979

 

-------------------------------------------------------------------------------------------

| Id  | Operation                    | Name         | Rows  | Bytes | Cost (%CPU)| Time          |

-------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT          |   |   2 |  4198 |      8   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID   | T2          |   1 |  2041 |      2   (0)| 00:00:01 |

|   2 |   NESTED LOOPS                       |   |   2 |  4198 |      8   (0)| 00:00:01 |

|   3 |    INLIST ITERATOR        |   |     |     |          |   |

|   4 |     TABLE ACCESS BY INDEX ROWID| T1          |   2 |   116 |      4   (0)| 00:00:01 |

|*  5 |      INDEX RANGE SCAN               | T1_N          |   2 |      |   2   (0)| 00:00:01 |

|*  6 |    INDEX RANGE SCAN           | T2_T1_ID |      1 |      |   1   (0)| 00:00:01 |

-------------------------------------------------------------------------------------------

 

Predicate Information (identified by operation id):

---------------------------------------------------

 

   5 - access("T1"."N"=18 OR "T1"."N"=19)

   6 - access("T1"."ID"="T2"."T1_ID")

 

Note

-----

   - dynamic sampling used for this statement

 

 

Statistics

----------------------------------------------------------

           0  recursive calls

           0  db block gets

          14  consistent gets

           0  physical reads

           0  redo size

       1164  bytes sent via SQL*Net to client

         492  bytes received via SQL*Net from client

           2  SQL*Net roundtrips to/from client

           0  sorts (memory)

           0  sorts (disk)

           2  rows processed

 

SQL>

 

特点:1、SQL语句被执行。故,执行计划结果的返回时间的快慢,取决于SQL语句执行时间的长短。有SQL语句执行结果的输出。

         2、有统计信息

 

     方法3:dbms_xplan.display_cursor
使用ORACLE数据库内置的dbms_xplan包来获取执行计划,也是常用的方法之一。根据调用包中过程及参数的不同,可以衍生出很多种方法。这里我们只介绍最常用的2种。
注意,我们这里使用的是 dbms_xplan.display_cursor,而不是方法1中使用的dbms_xplan.display,虽然同属一个包,但方法是不同的,不要搞混。

(1)、
设置会话选项为statistics_level=all后,用dbms_xplan.display_cursor(null,null,’allstats last’)查看执行计划。

SQL> alter session set statistics_level=all ;

SQL> SET AUTOTRACE OFF             --如果此前该开关为ON的状态,会影响我们后续的执行计划的获取和输出。所以,这里的目的是确保该开关已关闭。                

SQL> SELECT  * FROM t1, t2 WHERE t1.id = t2.t1_id AND t1.n in(18,19);

 

         ID         N

---------- ----------

CONTENTS

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


-------------------------------------------------------------------------------------------------------------------------------------------------------------------

         ID     T1_ID              N

---------- ---------- ----------

CONTENTS

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


-------------------------------------------------------------------------------------------------------------------------------------------------------------------

         18        18

yFfYpcNtsxEpvWUOceJmHtvpCEbcJTUTeKExdHlGlwoIFEgmOo

         18        18             18

OWCPIKKFQTMBZAVJBUGPOGOZGPHCMTGFDJTMCIZXRFVXYCATTY

 

         19        19

jAOYAJHBzwhNWHImZeFUOaxvMycbQsCLKhsUnSFwZpyctEahjK

         19        19             19

BEQUUMJSUDRLTCGOCIUHSZCNNJOTZOCEQKBZPSLHGAKRTLJAHX

 

 

SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));

 

PLAN_TABLE_OUTPUT

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


---------------------------------------------------------------

SQL_ID     cshvm6ngravw0, child number 0

-------------------------------------

SELECT     * FROM t1, t2 WHERE t1.id = t2.t1_id AND t1.n in(18,19)

 

Plan hash value: 128660979

 

-----------------------------------------------------------------------------------------------------

| Id  | Operation                    | Name         | Starts | E-Rows | A-Rows |       A-Time   | Buffers |

-----------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT          |   |   0 |      |          0 |00:00:00.01 |           0 |

|   1 |  TABLE ACCESS BY INDEX ROWID   | T2          |   1 |    1 |            2 |00:00:00.01 |         14 |

|   2 |   NESTED LOOPS                       |   |   1 |    2 |            5 |00:00:00.01 |         12 |

|   3 |    INLIST ITERATOR        |   |   1 |      |          2 |00:00:00.01 |           7 |

|   4 |     TABLE ACCESS BY INDEX ROWID| T1          |   2 |    2 |            2 |00:00:00.01 |           7 |

|*  5 |      INDEX RANGE SCAN               | T1_N          |   2 |    2 |            2 |00:00:00.01 |           5 |

|*  6 |    INDEX RANGE SCAN           | T2_T1_ID |      2 |    1 |            2 |00:00:00.01 |           5 |

-----------------------------------------------------------------------------------------------------

 

Predicate Information (identified by operation id):

---------------------------------------------------

 

   5 - access(("T1"."N"=18 OR "T1"."N"=19))

   6 - access("T1"."ID"="T2"."T1_ID")

 

Note

-----

   - dynamic sampling used for this statement

 

 

28 rows selected.

 

特点:1、SQL语句只有被执行过,才能得到其执行计划。故,得到执行计划时间的快慢,取决于SQL语句运行时间的长短。有SQL语句执行结果的输出。

        2、可以看到表被访问的次数(执行计划中的STARTS列内容)。

        3、可以看到执行计划各步骤中,实际得到的结果集行数(A-ROWS)与评估得到的结果集行数(E-ROWS)。利用该信息,可以判断统计信息是否准确。

        4、可以看到各执行计划步骤实际经历的时间(A-TIME),利用该信息,可以快速找到最耗时的执行计划步骤。

        5、无统计信息的输出,但执行计划中有逻辑读次数的信息(执行计划中的BUFFERS列内容)。

 

     (2)、 dbms_xplan.display_cursor()输入SQL_ID的方法
先通过以下SQL,获取相应SQL的SQL_ID.
 注:使用这种方法,要求相应SQL的执行计划还在内存中,即还没有被排出SHARED POOL。否则,查询结果会为空。

SQL>  SELECT sql_id,CHILD_NUMBER FROM v$sql A WHERE sql_text LIKE 'SELECT  * FROM t1, t2 WHERE t1.id = t2.t1_id AND t1.n in(18,19)%';

 

SQL_ID           CHILD_NUMBER

------------- ------------

cshvm6ngravw0                0

 

SQL> select * from table(dbms_xplan.display_cursor('cshvm6ngravw0'));

 

PLAN_TABLE_OUTPUT

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


---------------------------------------------------------------

SQL_ID     cshvm6ngravw0, child number 0

-------------------------------------

SELECT     * FROM t1, t2 WHERE t1.id = t2.t1_id AND t1.n in(18,19)

 

Plan hash value: 128660979

 

-------------------------------------------------------------------------------------------

| Id  | Operation                    | Name         | Rows  | Bytes | Cost (%CPU)| Time          |

-------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT          |   |    |     |   8 (100)|      |

|   1 |  TABLE ACCESS BY INDEX ROWID   | T2          |   1 |  2041 |      2   (0)| 00:00:01 |

|   2 |   NESTED LOOPS                       |   |   2 |  4198 |      8   (0)| 00:00:01 |

|   3 |    INLIST ITERATOR        |   |     |     |          |   |

|   4 |     TABLE ACCESS BY INDEX ROWID| T1          |   2 |   116 |      4   (0)| 00:00:01 |

|*  5 |      INDEX RANGE SCAN               | T1_N          |   2 |      |   2   (0)| 00:00:01 |

|*  6 |    INDEX RANGE SCAN           | T2_T1_ID |      1 |      |   1   (0)| 00:00:01 |

-------------------------------------------------------------------------------------------

 

Predicate Information (identified by operation id):

---------------------------------------------------

 

   5 - access(("T1"."N"=18 OR "T1"."N"=19))

   6 - access("T1"."ID"="T2"."T1_ID")

 

Note

-----

   - dynamic sampling used for this statement

 

 

28 rows selected.

 

特点:1、SQL语句只有被执行过,才能得到其执行计划。故,得到执行计划时间的快慢,取决于SQL语句运行时间的长短。有SQL语句执行结果的输出。

         2、无统计信息


因篇幅所限,余下内容请点击以下链接:

《如何获取真实的执行计划(下)》  http://bfc99.blog.51cto.com/265386/1706842

你可能感兴趣的:(执行计划,真实)