要为一个语句生成执行计划,可以有3种方法:
1).最简单的办法
Sql> set autotrace onSql> select * from dual;执行完语句后,会显示explain plan 与 统计信息。这个语句的优点就是它的缺点,这样在用该方法查看执行时间较长的sql语句时,需要等待该语句执行成功后,才返回执行计划,使优化的周期大大增长。
如果不想执行语句而只是想得到执行计划可以采用:Sql> set autotrace traceonly这样,就只会列出执行计划,而不会真正的执行语句,大大减少了优化时间。虽然也列出了统计信息,但是因为没有执行语句,所以该统计信息没有用处,如果执行该语句时遇到错误,解决方法为:
(1)在要分析的用户下:Sqlplus > @ ?\rdbms\admin\utlxplan.sql
(2) 用sys用户登陆Sqlplus > @ ?\sqlplus\admin\plustrce.sqlSqlplus > grant plustrace to user_name; - - user_name是上面所说的分析用户
2).用explain plan命令
(1) sqlplus > @ ?\rdbms\admin\utlxplan.sql
(2) sqlplus > explain plan set statement_id =’???’ for select ………………
注意,用此方法时,并不执行sql语句,所以只会列出执行计划,不会列出统计信息,并且执行计划只存在plan_table中。所以该语句比起set autotrace traceonly可用性要差。需要用下面的命令格式化输出,所以这种方式我用的不多:
set linesize 150
set pagesize 500
col PLANLINE for a120
SELECT EXECORD EXEC_ORDER, PLANLINE
FROM (SELECT PLANLINE, ROWNUM EXECORD, ID, RID
FROM (SELECT PLANLINE, ID, RID, LEV
FROM (SELECT lpad(' ',2*(LEVEL),rpad(' ',80,' '))||
OPERATION||' '|| -- Operation
DECODE(OPTIONS,NULL,'','('||OPTIONS || ') ')|| -- Options
DECODE(OBJECT_OWNER,null,'','OF '''|| OBJECT_OWNER||'.')|| -- Owner
DECODE(OBJECT_NAME,null,'',OBJECT_NAME|| ''' ')|| -- Object Name
DECODE(OBJECT_TYPE,null,'','('||OBJECT_TYPE|| ') ')|| -- Object Type
DECODE(ID,0,'OPT_MODE:')|| -- Optimizer
DECODE(OPTIMIZER,null,'','ANALYZED','', OPTIMIZER)||
DECODE(NVL(COST,0)+NVL(CARDINALITY,0)+NVL(BYTES,0),
0,null,' (COST='||TO_CHAR(COST)||',CARD='||
TO_CHAR(CARDINALITY)||',BYTES='||TO_CHAR(BYTES)||')')
PLANLINE, ID, LEVEL LEV,
(SELECT MAX(ID)
FROM PLAN_TABLE PL2
CONNECT BY PRIOR ID = PARENT_ID
AND PRIOR STATEMENT_ID = STATEMENT_ID
START WITH ID = PL1.ID
AND STATEMENT_ID = PL1.STATEMENT_ID) RID
FROM PLAN_TABLE PL1
CONNECT BY PRIOR ID = PARENT_ID
AND PRIOR STATEMENT_ID = STATEMENT_ID
START WITH ID = 0
AND STATEMENT_ID = 'aaa')
ORDER BY RID, -LEV))
ORDER BY ID;
上面这2种方法只能为在本会话中正在运行的语句产生执行计划,即我们需要已经知道了哪条语句运行的效率很差,我们是有目的只对这条SQL语句去优化。其实,在很多情况下,我们只会听一个客户抱怨说现在系统运行很慢,而我们不知道是哪个SQL引起的。此时有许多现成的语句可以找出耗费资源比较多的语句,如:
SELECT ADDRESS,
substr(SQL_TEXT,1,20) Text,
buffer_gets,
executions,
buffer_gets/executions AVG
FROM v$sqlarea
WHERE executions>0
AND buffer_gets > 100000
ORDER BY 5;
从而对找出的语句进行进一步优化。当然我们还可以为一个正在运行的会话中运行的所有SQL语句生成执行计划,这需要对该会话进行跟踪,产生trace文件,然后对该文件用tkprof程序格式化一下,这种得到执行计划的方式很有用,因为它包含其它额外信息,如SQL语句执行的每个阶段(如Parse、Execute、Fetch)分别耗费的各个资源情况(如CPU、DISK、elapsed等)。
3).用dbms_system存储过程生成执行计划
因为使用dbms_system存储过程可以跟踪另一个会话发出的sql语句,并记录所使用的执行计划,而且还提供其它对性能调整有用的信息。因其使用方式与上面2种方式有些不太一样,所以在附录中单独介绍。这种方法是对SQL进行调整比较有用的方式之一,有些情况下非它不可。具体内容参见附录。
例1:
假设LARGE_TABLE是一个较大的表,且username列上没有索引,则运行下面的语句:
SQL> SELECT * FROM LARGE_TABLE where USERNAME = ‘TEST’;
Query Plan
-----------------------------------------
SELECT STATEMENT Optimizer=CHOOSE (Cost=1234 Card=1 Bytes=14)
TABLE ACCESS FULL LARGE_TABLE [:Q65001] [ANALYZED]
在这个例子中,TABLE ACCESS FULL LARGE_TABLE是第一个操作,意思是在LARGE_TABLE表上做全表扫描。当这个操作完成之后,产生的row source中的数据被送往下一步骤进行处理,在此例中,SELECT STATEMENT操作是这个查询语句的最后一步。
Optimizer=CHOOSE 指明这个查询的optimizer_mode,即optimizer_mode初始化参数指定的值,它并不是指语句执行时真的使用了该优化器。决定该语句使用何种优化器的唯一方法是看后面的cost部分。例如,如果给出的是下面的形式,则表明使用的是CBO优化器,此处的cost表示优化器认为该执行计划的代价:
SELECT STATEMENT Optimizer=CHOOSE (Cost=1234 Card=1 Bytes=14)
然而假如执行计划中给出的是类似下面的信息,则表明是使用RBO优化器,因为cost部分的值为空,或者压根就没有cost部分。
SELECT STATEMENT Optimizer=CHOOSE Cost=
SELECT STATEMENT Optimizer=CHOOSE
这样我们从Optimizer后面的信息中可以得出执行该语句时到底用了什么样的优化器。特别的,如果Optimizer=ALL_ROWS| FIRST_ROWS| FIRST_ROWS_n,则使用的是CBO优化器;如果Optimizer=RULE,则使用的是RBO优化器。
cost属性的值是一个在oracle内部用来比较各个执行计划所耗费的代价的值,从而使优化器可以选择最好的执行计划。不同语句的cost值不具有可比性,只能对同一个语句的不同执行计划的cost值进行比较。
[:Q65001] 表明该部分查询是以并行方式运行的。里面的数据表示这个操作是由并行查询的一个slave进程处理的,以便该操作可以区别于串行执行的操作。
[ANALYZED] 表明操作中引用的对象被分析过了,在数据字典中有该对象的统计信息可以供CBO使用。
例2:
假定A、B、C都是不是小表,且在A表上一个组合索引:A(a.col1,a.col2) ,注意a.col1列为索引的引导列。
考虑下面的查询:
select A.col4
from A , B , C
where B.col3 = 10 and A.col1 = B.col1 and A.col2 = C.col2 and C.col3 = 5
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 MERGE JOIN
&nb