您的位置:首页 > 数据库 > Oracle

[Oracle 10g] SQL Plan (Explain Plan/ DBMS_XPLAN) & Autotrace Enhancement in 10g

2010-01-07 09:41 549 查看
我们知道查询一条SQL的执行计划,一般可以通过如下两种方式(当然还有其他方式)

(1)Explainplanfor/DBMS_XPLAN.DISPLAY

(2)Setautotraceon

Explainplanfor和Setautotrace都是SQL*PLUS命令,DBMS_XPLAN是Oracle提供的查询执行计划相关的包。

这两种方法在Oracle10g都得到了加强。DBMS_XPLAN最先是在Oracle9.2中引入的,但是只能用来查看SQL的“理论”上的执行计划(Explainplanfor的结果),在10g中,可以通过新增加的DISPLAY_CURSOR来得到SQL(CURSOR)的“实际”执行计划信息。

(Tom在<EffectiveOraclebyDesign>中提到如何在10g之前如何用DBMS_XPLAN.DISPLAY和V$SQL来得到实际执行的信息,下面会提到)

Autotrace提供了很多种关于SQL执行的信息,其中之一是SQL的执行计划(同样也是“理论”上的,不是实际的),但是Autotrace返回的其他统计信息(physical/logicali/o)却是实际的。在10.2之前,Autotrace用的是自己的format方法,因此得到的SQL执行计划表同用DBMS_XPLAN不是很一致,但是从10.2开始,autotrace采用了DBMS_XPLAN的方法来格式化最后输出的执行计划表。

需要注意的是,DBMS_XPLAN(确切说是EXPLAINPLANfor)和autotrace都依赖于表PLAN_TABLE,可能需要手动创建一下。用autotrace还需要当前用户被被授予PLUSTRACErole.关于如何进行设置EXPLAINPLAN和Autotrace,参考另外一篇blog。

1.AboutDBMS_XPLAN

包DBMS_XPLAN在Oracle9iR2中引入的,用来查看ExplainPlan生成的执行计划。

10g中,DBMS_XPLAN增加了用来查看SQL的实际执行的计划相关信息(DBMS_XPLAN.DISPLAY_CURSOR)。

(可以用DESCRIBE查看包DBMS_XPLAN中的信息)
[code]SQL>descDBMS_XPLAN
FUNCTIONDISPLAYRETURNSDBMS_XPLAN_TYPE_TABLE
ArgumentNameTypeIn/OutDefault?
-------------------------------------------------------------------
TABLE_NAMEVARCHAR2INDEFAULT
STATEMENT_IDVARCHAR2INDEFAULT
FORMATVARCHAR2INDEFAULT
FILTER_PREDSVARCHAR2INDEFAULT
FUNCTIONDISPLAY_AWRRETURNSDBMS_XPLAN_TYPE_TABLE
ArgumentNameTypeIn/OutDefault?
-------------------------------------------------------------------
SQL_IDVARCHAR2IN
PLAN_HASH_VALUENUMBER(38)INDEFAULT
DB_IDNUMBER(38)INDEFAULT
FORMATVARCHAR2INDEFAULT
FUNCTIONDISPLAY_CURSORRETURNSDBMS_XPLAN_TYPE_TABLE
ArgumentNameTypeIn/OutDefault?
-------------------------------------------------------------------
SQL_IDVARCHAR2INDEFAULT
CURSOR_CHILD_NONUMBER(38)INDEFAULT
FORMATVARCHAR2INDEFAULT
FUNCTIONDISPLAY_SQLSETRETURNSDBMS_XPLAN_TYPE_TABLE
ArgumentNameTypeIn/OutDefault?
-------------------------------------------------------------------
SQLSET_NAMEVARCHAR2IN
SQL_IDVARCHAR2IN
PLAN_HASH_VALUENUMBER(38)INDEFAULT
FORMATVARCHAR2INDEFAULT
SQLSET_OWNERVARCHAR2INDEFAULT
FUNCTIONFORMAT_NUMBERRETURNSVARCHAR2
ArgumentNameTypeIn/OutDefault?
-------------------------------------------------------------------
NUMNUMBERIN
FUNCTIONFORMAT_NUMBER2RETURNSVARCHAR2
ArgumentNameTypeIn/OutDefault?
-------------------------------------------------------------------
NUMNUMBERIN
FUNCTIONFORMAT_SIZERETURNSVARCHAR2
ArgumentNameTypeIn/OutDefault?
-------------------------------------------------------------------
NUMNUMBERIN
FUNCTIONFORMAT_SIZE2RETURNSVARCHAR2
ArgumentNameTypeIn/OutDefault?
-------------------------------------------------------------------
NUMNUMBERIN
FUNCTIONPREPARE_RECORDSRETURNSDBMS_XPLAN_TYPE_TABLE
ArgumentNameTypeIn/OutDefault?
-------------------------------------------------------------------
PLAN_CURREFCURSORIN
I_FORMAT_FLAGSBINARY_INTEGERIN
FUNCTIONVALIDATE_FORMATRETURNSBOOLEAN
ArgumentNameTypeIn/OutDefault?
-------------------------------------------------------------------
HASPLANSTATSBOOLEANIN
FORMATVARCHAR2IN
FORMAT_FLAGSBINARY_INTEGEROUT
SQL>
[/code]

2.ColumnProjections

所谓columnprojections就是指DBMS_XPLAN给出的信息中包含了SQL执行计划中每一步实际选择的列的信息,这个有助于我们理解SQL执行计划每一步的实际动作。

以Scott中的表作为例子,


[code]SQL>EXPLAINPLANsetstatement_id='X1'
2FOR
3SELECTd.deptno
4,d.dname
5,COUNT(*)ascount_employees
6,SUM(e.sal)assum_salaries
7FROMdeptd
8,empe
9WHEREd.deptno=e.deptno
10GROUPBY
11d.deptno
12,d.dname;
Explained.
[/code]
下面通过调用DBMS_XPLAN.DISPLAY来查看上面这条SQL语句的执行计划,
(从DBMS_XPLAN.DISPLAY的函数接口可以看出,可以直接调用DBMS_XPLAN.DISPLAY,而不用传入任何参数,这样我们会得到刚刚执行的SQL语句的计划)

[code]SQL>SELECTplan_table_output
2FROMTABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE','X1','ALL'));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------
------------------------------------------------------------
Planhashvalue:2708255165
-----------------------------------------------------------------------------------------
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
-----------------------------------------------------------------------------------------
|0|SELECTSTATEMENT||9|180|7(29)|00:00:01|
|1|HASHGROUPBY||9|180|7(29)|00:00:01|
|2|MERGEJOIN||14|280|6(17)|00:00:01|
|3|TABLEACCESSBYINDEXROWID|DEPT|4|52|2(0)|00:00:01|
|4|INDEXFULLSCAN|PK_DEPT|4||1(0)|00:00:01|
|*5|SORTJOIN||14|98|4(25)|00:00:01|
|6|TABLEACCESSFULL|EMP|14|98|3(0)|00:00:01|
-----------------------------------------------------------------------------------------
QueryBlockName/ObjectAlias(identifiedbyoperationid):
-------------------------------------------------------------
1-SEL$1
3-SEL$1/D@SEL$1
4-SEL$1/D@SEL$1
6-SEL$1/E@SEL$1
PredicateInformation(identifiedbyoperationid):
---------------------------------------------------
5-access("D"."DEPTNO"="E"."DEPTNO")
filter("D"."DEPTNO"="E"."DEPTNO")
[/code]
ColumnProjectionInformation(identifiedbyoperationid):
-----------------------------------------------------------
1-(#keys=2)"D"."DEPTNO"[NUMBER,22],"D"."DNAME"[VARCHAR2,14],
COUNT(*)[22],SUM("E"."SAL")[22]
2-(#keys=0)"D"."DEPTNO"[NUMBER,22],"D"."DNAME"[VARCHAR2,14],
"E"."SAL"[NUMBER,22]
3-"D"."DEPTNO"[NUMBER,22],"D"."DNAME"[VARCHAR2,14]
4-"D".ROWID[ROWID,10],"D"."DEPTNO"[NUMBER,22]
5-(#keys=1)"E"."DEPTNO"[NUMBER,22],"E"."SAL"[NUMBER,22]
6-"E"."SAL"[NUMBER,22],"E"."DEPTNO"[NUMBER,22]
39rowsselected.
返回结果的最后一部分就是关于ColumnProjection,从中women可以看到SQL执行每一步返回的列的信息。

3.QueryBlocks

QueryBlock部分在2中的执行计划信息中也可以看到。

关于QueryBlock的详细信息,可以参见AdrianBillington的原文。

4.ViewingactualexecutionplanswithDBMS_XPLAN

9i中DBMS_XPLAN只是提供了“理论”上的的SQL执行计划(通过ExplainPlan).不过,9i提供了几个动态视图来供查询实际的SQL(cursor)执行计划信息,比如v$SQL_PLAN,v$SQL_PLAN_STATISTICS).虽然如此,DBMS_XPLAN却没有能够提供返回容易阅读的格式化好的实际执行计划信息。

10g中这个问题得到了解决,DBMS_XPLAN中增加的Function,DISPLAY_CURSOR,用来返回格式化好(就像DISPLAY一样)的SQL实际执行的信息。DISPLAY_CURSOR主要是依赖于Oracle的几个动态视图,包括v$SQL,v$SQL_PLAN,v$SQL_PLAN_STATISTICS_ALL等。

下面来看看如何使用DISPLAY_CURSOR,

SQL>SELECTd.dname
2,SUM(e.sal)ASsum_sal
3FROMdeptd
4,empe
5WHEREd.deptno=e.deptno
6GROUPBY
7d.dname;
DNAMESUM_SAL
------------------------
ACCOUNTING8750
RESEARCH10875
SALES9400
SQL>SELECTplan_table_output
2FROMTABLE(DBMS_XPLAN.DISPLAY_CURSOR);
PLAN_TABLE_OUTPUT
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
UserhasnoSELECTprivilegeonV$SQL_PLAN

上面说到DISPLAY_CURSOR依赖于视图V$SQL_PLAN,因此需要赋予scott这个权限,

SQL>showuser
USERis"SYS"

SQL>grantselectonv_$sql_plantoscott;
Grantsucceeded.
下面重新来过~

[code]SQL>setserveroutputoff
SQL>
SQL>SELECTd.dname
2,SUM(e.sal)ASsum_sal
3FROMdeptd
4,empe
5WHEREd.deptno=e.deptno
6GROUPBY
7d.dname;
DNAMESUM_SAL
------------------------
ACCOUNTING8750
RESEARCH10875
SALES9400
SQL>
SQL>SELECTplan_table_output
2FROMTABLE(DBMS_XPLAN.DISPLAY_CURSOR);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------
------------------------------------------------------------
SQL_IDfb38ja6gkq5wp,childnumber0
-------------------------------------
WARNING:UserhasnoSELECTprivilegesonV$SQL
Planhashvalue:2708255165
-----------------------------------------------------------------------------------------
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
-----------------------------------------------------------------------------------------
|0|SELECTSTATEMENT||||7(100)||
|1|HASHGROUPBY||4|80|7(29)|00:00:01|
|2|MERGEJOIN||14|280|6(17)|00:00:01|
|3|TABLEACCESSBYINDEXROWID|DEPT|4|52|2(0)|00:00:01|
|4|INDEXFULLSCAN|PK_DEPT|4||1(0)|00:00:01|
|*5|SORTJOIN||14|98|4(25)|00:00:01|
|6|TABLEACCESSFULL|EMP|14|98|3(0)|00:00:01|
-----------------------------------------------------------------------------------------
PredicateInformation(identifiedbyoperationid):
---------------------------------------------------
5-access("D"."DEPTNO"="E"."DEPTNO")
filter("D"."DEPTNO"="E"."DEPTNO")
24rowsselected.
SQL>
[/code]

注意返回的结果里面有个WARNING:UserhasnoSELECTpriviledgeonV$SQL,说明我们还需要赋予scott该权限。

注意调用DISPLAY_CURSOR的时候,我们没有传入任何参数,这样的话这个函数会返回当前Session中最后一个执行的SQL(cursor)的执行计划信息。由于sqlplus默认会调用DBMS_OUTPUT.GET_LINES,影响到DISPLAY_CURSOR返回的结果,因此我们首先setserveroutputoff。

---Tom’sSolutionin<EffectiveOraclebyDesign>inOracle9.2toviewactualexecutionplan

首先创建一个视图(也可以创建一个实际的表)用来充当PLAN_TABLE的角色,只不过这次“存储”(因为是视图,只是动态从v$sql_plan里面得到)的是之前运行过的SQL语句的实际的执行计划。


[code]CREATEORREPLACEVIEWdynamic_plan_table
AS
SELECT
RAWTOHEX(address)||'_'||child_numberASstatement_id
,SYSDATEtimestamp
,operation
,options
,object_node
,object_owner
,object_name
,0object_instance
,optimizer
,search_columns
,id
,parent_id
,position
,cost
,cardinality
,bytes
,other_tag
,partition_start
,partition_stop
,partition_id
,other
,distribution
,cpu_cost
,io_cost
,temp_space
,access_predicates
,filter_predicates
FROMv$sql_plan;
[/code]

然后通过DBMS_XPLAN.DISPLAY来格式化输出结果,只不过对于DISPLAY的参数要做一些特殊处理,


[code]SELECTplan_table_output
FROMTABLE(dbms_xplan.display
('dynamic_plan_table',
(selectrawtohex(address)||'_'||child_numberx
fromv$sql
wheresql_text='select*fromtt1whereobject_id>32000'),
'serial'))
[/code]

可以看出DBMS_XPLAN.DISPLAY的第一个参数的值是dynamic_plan_table,就是刚才创建的view,这就让DBMS_XPLAN到刚才创建的视图里“取”数据,而不是默认的PLAN_TABLE。第二个参数的SQL语句是取获得之前执行的SQL语句对应的Statemnt_ID.第三个参数'serial’是为了向后兼容,可以换成'ALL’

5.IdentifyingSpecificSQLCursors

DISPLAY_CURSOR可以用来查询某个具体的SQLCURSOR的实际执行信息,不过它需要传入一个参数:SQL_ID.(有时候还需要CHILD_CURSOR_NO参数)

SQL_ID是Oracle10g新增加的,在很多动态视图里面都存在,用来标示一条SQL语句。

需要注意的是,SQL_ID只是跟在sharedpool里面的SQL语句的字符串(TEXT)是一一对应的,但并不是于SQL语句对应的Cursor是一一对应的。因为一条SQL语句(TEXT)可能会对应于多个childcursors(不同的执行计划).正是因为这个原因,DISPLAY_CURSOR还接受另外一个参数—childcursorno(默认值为0,因为大多数情况下每条SQL语句对应一个cursor)

另外,一个Cusor(SQL_ID,CHILD_CURSOR)的执行计划也可能随着时间的迁移而变化,这个会在动态视图v$SQL_PLAN中以新的一条PLAN_HASH_VALUE来体现。

动态视图V$SESSION在Oracle10G中也得到了加强,这个视图多出来几列来显示SQL_ID/SQL_CHILD_NUMBER,PREV_SQL_ID/PREV_CHILD_NUMBER,这可以帮助我们定位到刚刚执行的的SQL语句。

为了通过DISPLAY_CURSOR得到具体某个SQL(cursor)实际的执行计划,显然我们需要得到该SQL的SQL_ID和CHILD_NUMBER).可以通过查询动态视图v$SQL来得到SQL_ID。


[code]SQL>connscott/scott
Connected.
SQL>SELECTd.dname
2,SUM(e.sal)ASsum_sal
3FROMdeptd
4,empe
5WHEREd.deptno=e.deptno
6GROUPBY
7d.dname;
DNAMESUM_SAL
------------------------
ACCOUNTING8750
RESEARCH10875
SALES9400
SQL>
SQL>SELECTsql_id
2,child_number
3,sql_text
4FROMv$sql
5WHERELOWER(sql_text)LIKE'selectd.dname%';
SQL_IDCHILD_NUMBERSQL_TEXT
-----------------------------------------------------------------
00chu48sqmz9p0SELECTd.dname,SUM(e.sal)ASsum_
salFROMdeptd,empeWHEREd
.deptno=e.deptnoGROUPBYd.dn
ame
SQL>
[/code]

得到了SQL_ID和CHILD_NUMBER就可以调用DBMS_XPLAN.DISPLAY_CURSOR来得到这条SQL的实际执行信息了,


[code]SQL>SELECTplan_table_output
2FROMTABLE(DBMS_XPLAN.DISPLAY_CURSOR('00chu48sqmz9p',0,'ALL'));
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------
SQL_ID00chu48sqmz9p,childnumber0
-------------------------------------
SELECTd.dname,SUM(e.sal)ASsum_salFROMdeptd,empe
WHEREd.deptno=e.deptnoGROUPBYd.dname
Planhashvalue:2708255165
-----------------------------------------------------------------------------------------
|Id|Operation|Name|Rows|Bytes|Cost(%CPU)|Time|
-----------------------------------------------------------------------------------------
|0|SELECTSTATEMENT||||7(100)||
|1|HASHGROUPBY||4|80|7(29)|00:00:01|
|2|MERGEJOIN||14|280|6(17)|00:00:01|
|3|TABLEACCESSBYINDEXROWID|DEPT|4|52|2(0)|00:00:01|
|4|INDEXFULLSCAN|PK_DEPT|4||1(0)|00:00:01|
|*5|SORTJOIN||14|98|4(25)|00:00:01|
|6|TABLEACCESSFULL|EMP|14|98|3(0)|00:00:01|
-----------------------------------------------------------------------------------------
QueryBlockName/ObjectAlias(identifiedbyoperationid):
-------------------------------------------------------------
1-SEL$1
3-SEL$1/D@SEL$1
4-SEL$1/D@SEL$1
6-SEL$1/E@SEL$1
PredicateInformation(identifiedbyoperationid):
---------------------------------------------------
5-access("D"."DEPTNO"="E"."DEPTNO")
filter("D"."DEPTNO"="E"."DEPTNO")
ColumnProjectionInformation(identifiedbyoperationid):
-----------------------------------------------------------
1-"D"."DNAME"[VARCHAR2,14],SUM("E"."SAL")[22]
2-"D"."DNAME"[VARCHAR2,14],"E"."SAL"[NUMBER,22]
3-"D"."DEPTNO"[NUMBER,22],"D"."DNAME"[VARCHAR2,14]
4-"D".ROWID[ROWID,10],"D"."DEPTNO"[NUMBER,22]
5-(#keys=1)"E"."DEPTNO"[NUMBER,22],"E"."SAL"[NUMBER,22]
6-"E"."SAL"[NUMBER,22],"E"."DEPTNO"[NUMBER,22]
43rowsselected.
SQL>
[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: