在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