Vous êtes sur la page 1sur 20

TUNING KEY TO ORACLE DATABASE APPLICATION : EXPLAIN PLAN

In relational database, the explain plan is the vehicle used to see which way the database will access the data. SQL statement tuning requires an understanding of explain plans. This article will help you understand the various parts of the explain plan and help you choose the best method for retrieving data from your racle database. racle tools include T!"# $ %which examines T#&'( files), and the (*"L&I+ command, combined with a SQL statement to display the results (xplain "lan is an racle function that analy,es SQL statements for performance. The results of the (xplain "lan tell you the order that racle will search-.oin the tables, the types of access that will be employed %indexed search or full table scan), and the names of indexes that will be used.The purpose of the (xplain "lan command is to determine the execution plan racle will follow to execute a specified SQL statement. This statement inserts a row describing each step of the execution plan into a specified table. If you are using cost/based optimi,ation, this statement also determines the cost of executing the statement. The explain plan is a necessity for tuning SQL statements for both rule/based and cost/ based optimi,ers Query speed is a perpetual challenge for anyone using a SQL database. 0any newer racle 1sers are unaware of the issues involved with designing a good query and those who have been at the game for some time want to ma2e sure they are not needlessly burdening the database server. If you use racle, (xplain "lan is a great way to tune your queries. &s a bonus for using (xplain "lan, you will learn more about how the 340S wor2s 5behind the scenes5, enabling you to write efficient queries the first time around

EXPLAIN PLAN Statement


4efore the database server can execute a SQL statement, racle must first parse the statement and develop an execution plan. The execution plan is a tas2 list of sorts that decomposes a potentially complex SQL operation into a series of basic data access operations. $or example, a query against the dept table might have an execution plan that consists of an index loo2up on the deptno index, followed by a table access by # 6I3. The (*"L&I+ "L&+ statement allows you to submit a SQL statement to racle and have the database prepare the execution plan for the statement without actually executing it. The execution plan is made available to you in the form of rows inserted into a special table called a plan table. 7ou may query the rows in the plan table using ordinary S(L('T statements in order to see the steps of the execution plan for the statement you explained. 7ou may 2eep multiple execution plans in the plan table by assigning each a unique statement8id. r you may choose to delete the rows from the plan table after you are finished loo2ing at the execution plan. 7ou can also roll bac2 an (*"L&I+ "L&+ statement in order to remove the execution plan from the plan table. The (*"L&I+ "L&+ statement runs very quic2ly, even if the statement being explained is a query that might run for hours. This is because the statement is simply parsed and its execution plan saved into the plan table. The actual statement is never executed by (*"L&I+ "L&+. &long these same lines, if the statement being explained includes bind

variables, the variables never need to actually be bound. The values that would be bound are not relevant since the statement is not actually executed. 7ou don9t need any special system privileges in order to use the (*"L&I+ "L&+ statement. :owever, you do need to have I+S(#T privileges on the plan table, and you must have sufficient privileges to execute the statement you are trying to explain. The one difference is that in order to explain a statement that involves views, you must have privileges on all of the tables that ma2e up the view. If you don9t, you9ll get an ; #&/ <=<>?@ insufficient privileges on underlying ob.ects of the viewA error. The columns that ma2e up the plan table are as follows@
Name Null? -------------------- -------STATEMENT_ID TIMESTAMP REMARKS PERATI N PTI NS !"ECT_N DE !"ECT_ $NER !"ECT_NAME !"ECT_INSTANCE !"ECT_T&PE PTIMI'ER SEARCH_C )%MNS ID PARENT_ID P SITI N C ST CARDINA)IT& !&TES THER_TA* PARTITI N_START PARTITI N_ST P PARTITI N_ID THER DISTRI!%TI N Type ------------VARCHAR2(30) DATE VARCHAR2(80) VARCHAR2(30) VARCHAR2(30) VARCHAR2(#28) VARCHAR2(30) VARCHAR2(30) N%M!ER(38) VARCHAR2(30) VARCHAR2(2(() N%M!ER N%M!ER(38) N%M!ER(38) N%M!ER(38) N%M!ER(38) N%M!ER(38) N%M!ER(38) VARCHAR2(2(() VARCHAR2(2(() VARCHAR2(2(() N%M!ER(38) ) N* VARCHAR2(30)

There are other ways to view execution plans besides issuing the (*"L&I+ "L&+ statement and querying the plan table. SQLB"lus can automatically display an execution plan after each statement is executed. &lso, there are many C1I tools available that allow you to clic2 on a SQL statement in the shared pool and view its execution plan. In addition, T!"# $ can optionally include execution plans in its reports as well.

Vehicle To Application Tuning: EXPLAIN PLAN & TKPROF


T!"# $ is a program that you invo2e at the operating system command prompt in order to reformat the trace file into a format that is much easier to comprehend. (ach SQL statement is displayed in the report, along with counts of how many times it was parsed, executed, and fetched. '"1 time, elapsed time, logical reads, physical reads, and rows processed are also reported, along with information about recursion level and misses in

the library cache. T!"# $ can also optionally include the execution plan for each SQL statement in the report, along with counts of how many rows were processed at each step of the execution plan. The SQL statements can be listed in a T!"# $ report in the order of how much resource they used, if desired. &lso, recursive SQL statements issued by the S7S user to manage the data dictionary can be included or excluded, and T!"# $ can write SQL statements from the traced session into a spool file. (*"L&I+ "L&+ and T!"# $ allow you to proactively tune an application while it is in development. It is relatively easy to enable SQL trace, run an application in a test environment, run T!"# $ on the trace file, and review the output to determine if application or schema changes are called for. (*"L&I+ "L&+ is handy for evaluating individual SQL statements. 4y reviewing execution plans, you can also validate the scalability of an application. If the database operations are dependent upon full table scans of tables that could grow quite large, then there may be scalability problems ahead. n the other hand, if large tables are accessed via selective indexes, then scalability may not be a problem. (*"L&I+ "L&+ and T!"# $ may also be used in an existing production environment in order to ,ero in on resource intensive operations and get insights into how the code may be optimi,ed. T!"# $ can further be used to quantify the resources required by specific database operations or application functions. (*"L&I+ "L&+ is also handy for estimating resource requirements in advance. Suppose you have an ad hoc reporting request against a very large database. #unning queries through (*"L&I+ "L&+ will let you determine in advance if the queries are feasible or if they will be resource intensive and will ta2e unacceptably long to run.

Gui eline! Fo" EXPLAIN PLAN An TKPROF


4efore you can use the (*"L&I+ "L&+ statement, you must have I+S(#T privileges on a plan table. The plan table can have any name you li2e, but the names and data types of the columns are not flexible. 7ou will find a script called utlxplan.sql in D #&'L(8: 0(-rdbms-admin that creates a plan table with the name plan8table in the local schema. If you use this script to create your plan table, you can be assured that the table will have the right definition for use with (*"L&I+ "L&+.
Explain Plan Table and Resul s

S+), E-P)AIN P)AN . R 2 /ele01 e2ame 3 345m emp 6 78e4e 9ep125 :2 (/ele01 9ep125 345m 9ep1 78e4e 9ep125 ;#0)< (xplained.

(xecution plans are a hierarchical arrangement of simple data access operations. 4ecause of the hierarchy, you need to use a ' ++('T 47 clause in your query from the plan table. 1sing the L"&3 function, you can cause the output to be formatted in such a way that the indenting helps you traverse the hierarchy. There are many different ways to format the data retrieved from the plan table. +o one query is the best, because the plan table holds a lot of detailed information. 3ifferent 34&s will find different aspects more useful in different situations.
S+), SE)ECT 5pe4a1:52= 5p1:52/= 5>?e01_2ame= :9= pa4e21_:9 2 345m pla2_1a>le< PERATI N ---------------SE)ECT STATEMENT NESTED ) PS INDETA!)E ACCESS PTI NS -----------!"ECT_NAME ---------------ID ---0 # 2 3 PARENT_ID --------0 # #

%NI+%E SCAN .%))

PK_DEPT EMP

TKPROF Ou pu Exa!ple
/ele01 @ 345m 1u154:alA0u4_emp_/1a1u/ 0all 05u21 0pu elap/e9 9:/B Cue4y 0u44e21 457/ ------- ------ -------- ---------- ------- ---------- --------- -----Pa4/e # 0A02 0A02 0 0 0 0 EDe0u1e # 0A00 0A00 0 0 0 0 .e108 2 0A23 0A2( ## #0(# 3 #( ------- ------ -------- ---------- ------- ---------- --------- ------

total

<.FG

<.FH

==

=<G=

>

A#TOTRA$E
SQLB"lus has an autotrace feature which allows you to automatically display execution plans and helpful statistics for each statement executed in a SQLB"lus session without having to use the (*"L&I+ "L&+ statement or query the plan table. 7ou turn this feature on and off with the following SQLB"lus command@ S(T &1T T#&'( $$I +IT#&'( +L7 J(*"L&I+K JST&TISTI'SK 6hen you turn on autotrace in SQLB"lus, the default behavior is for SQLB"lus to execute each statement and display the results in the normal fashion, followed by an execution plan listing and a listing of various server/side resources used to execute the statement. 4y using the T#&'( +L7 2eyword, you can have SQLB"lus suppress the query results. 4y using the (*"L&I+ or ST&TISTI'S 2eywords, you can have

SQLB"lus display .ust the execution plan without the resource statistics or .ust the statistics without the execution plan. In order to have SQLB"lus display execution plans, you must have privileges on a plan table by the name of plan8table. In order to have SQLB"lus display the resource statistics, you must have S(L('T privileges on vDsesstat, vDstatname, and vDsession. There is a script in D #&'L(8: 0(-sqlplus-admin called plustrce.sql which creates a role with these three privileges in it, but this script is not run automatically by the racle installer. The autotrace feature of SQLB"lus ma2es it extremely easy to generate and view execution plans, with resource statistics as an added bonus. ne 2ey drawbac2, however, is that the statement being explained must actually be executed by the database server before SQLB"lus will display the execution plan. This ma2es the tool unusable in the situation where you would li2e to predict how long an operation might ta2e to complete.

Anothe" Acce!!o"% To The Vehicle OF Tuning : TKPROF SQL Trace File :Input to TKPROF
SQL trace files contain detailed timing information. 4y default, racle does not trac2 timing, so all timing figures in trace files will show as ,ero. If you would li2e to see legitimate timing information, then you need to enable timed statistics. 7ou can do this at the instance level by setting the following parameter in the instance parameter file and restarting the instance@
1:me9_/1a1:/1:0/ ; 14ue

7ou can also dynamically enable or disable timed statistics collection at either the instance or the session level with the following commands@
A)TER S&STEM SET 1:me9_/1a1:/1:0/ ; TR%EE.A)SE< A)TER SESSI N SET 1:me9_/1a1:/1:0/ ; TR%EE.A)SE<

There is no 2nown way to enable timed statistics collection for an individual session from another session %a2in to the S7S.dbms8system.set8sql8trace8in8session built/in). There is very high overhead associated with enabling SQL trace. Some 34&s believe the performance penalty could be over FGL. &nother concern is that enabling SQL trace causes the generation of potentially large trace files. $or these reasons, you should use SQL trace sparingly. nly trace what you need to trace and thin2 very carefully before enabling SQL trace at the instance level. n the other hand, there is little, if any, measurable performance penalty in enabling timed statistics collection. 0any 34&s run production databases with timed statistics collection enabled at the system level so that various system statistics %more than .ust SQL trace files) will include detailed timing information. +ote that racle M.=.G had some serious memory corruption bugs associated with enabling timed statistics collection at the instance level, but these seem to have been fixed in racle M.=.N.

SQL trace may be enabled at the instance or session level. To enable SQL trace at the instance level, add the following parameter setting to the instance parameter file and restart the database instance@
/Cl_14a0e ; 14ue

6hen an racle instance starts up with the above parameter setting, every database session will run in SQL trace mode, meaning that all SQL operations for every database session will be written to trace files. (ven the daemon processes li2e "0 + and S0 + will be tracedO In practice, enabling SQL trace at the instance level is usually not very useful. It can be overpowering, sort of li2e using a fire hose to pour yourself a glass of water. It is more typical to enable SQL trace in a specific session. 7ou can turn SQL trace on and off as desired in order to trace .ust the operations that you wish to trace. If you have access to the database session you wish to trace, then use the &LT(# S(SSI + statement as follows to enable and disable SQL trace@
A)TER SESSI N SET /Cl_14a0e ; TR%EE.A)SE<

This technique wor2s well if you have access to the application source code and can add in &LT(# S(SSI + statements at will. It also wor2s well when the application runs from SQLB"lus and you can execute &LT(# S(SSI + statements at the SQLB"lus prompt before invo2ing the application. In situations where you cannot invo2e an &LT(# S(SSI + command from the session you wish to tracePas with prepac2aged applications, for examplePyou can connect to the database as a 34& user and invo2e the dbms8system built/in pac2age in order to turn on or off SQL trace in another session. 7ou do this by querying vDsession to find the SI3 and serial number of the session you wish to trace and then invo2ing the dbms8system pac2age with a command of the form@
E-EC%TE S&SA9>m/_/y/1emA/e1_/Cl_14a0e_:2_/e//:52 (FSID,= F/e4:alG,= TR%EE.A)SE)<

6hen you enable SQL trace in a session for the first time, the racle server process handling that session will create a trace file in the directory on the database server designated by the user8dump8dest initiali,ation parameter. &s the server is called by the application to perform database operations, the server process will append to the trace file. +ote that tracing a database session that is using multi/threaded server %0TS) is a bit complicated because each database request from the application could get pic2ed up by a different server process. In this situation, each server process will create a trace file containing trace information about the operations performed by that process only. This means that you will potentially have to combine multiple trace files together to get the full picture of how the application interacted with the database. $urthermore, if multiple

sessions are being traced at once, it will be hard to tell which operations in the trace file belong to which session. $or these reasons, you should use dedicated server mode when tracing a database session with SQL trace.

Generating TKPROF
To run T!"# $ specifying the name of a SQL trace file and an output filename. T!"# $ will read the trace file and generate a report file with the output filename you specified. T!"# $ will not connect to the database, and the report will not include execution plans for the SQL statements. SQL statements that were executed by the S7S user recursively %to dynamically allocate an extent in a dictionary/managed tablespace, for example) will be included in the report, and the statements will appear in the report approximately in the order in which they were executed in the database session that was traced. racle writes trace files on the database server to the directory specified by the user8dump8dest initiali,ation parameter. %3aemon processes such as "0 + write their trace files to the directory specified by bac2ground8dump8dest.) n 1nix platforms, the trace file will have a name that incorporates the operating system "I3 of the server process writing the trace file. If there are a lot of trace files in the user8dump8dest directory, it could be tric2y to find the one you want. ne tactic is to examine the timestamps on the files. &nother technique is to embed a comment in a SQL statement in the application that will ma2e its way into the trace file. &n example of this is as follows@
A)TER SESSI N SET /Cl_14a0e ; TR%E<

4ecause T!"# $ is a utility you invo2e from the operating system and not from within a database session, there will naturally be some variation in the user interface from one operating system platform to another. n 1nix platforms, you run T!"# $ from the operating system prompt with a syntax as follows@
1Bp453 F14a0e 3:le, F5u1pu1 3:le, HeDpla:2;Fu/e42ameIpa//7549,J H/541;FBey7549,J

If you invo2e T!"# $ with no arguments at all, you will get a help screen listing all of the options. This is especially helpful because T!"# $ offers many sort capabilities, but you select the desired sort by specifying a cryptic 2eyword. The help screen identifies all of the sort 2eywords. If you specify sysQn, T!"# $ will exclude from the report SQL statements initiated by racle as the S7S user. This will ma2e your report loo2 tidier because it will only contain statements actually issued by your application. The theory is that racle internal SQL has already been fully optimi,ed by the 2ernel developers at racle 'orporation, so you should not have to deal with it. :owever, using sysQn will exclude potentially valuable information from the T!"# $ report. Suppose the SC& is not properly si,ed on the instance and racle is spending a lot of time resolving dictionary cache misses. This

would manifest itself in lots of time spent on recursive SQL statements initiated by the S7S user. 1sing sysQn would exclude this information from the report. If you specify the insert 2eyword, T!"# $ will generate a SQL script in addition to the regular report. This SQL script creates a table called t2prof8table and inserts one row for each SQL statement displayed on the report. The row will contain the text of the SQL statement traced and all of the statistics displayed in the report. 7ou could use this feature to effectively load the T!"# $ report into the database and use SQL to analy,e and manipulate the statistics. I9ve never needed to use this feature, but I suppose it could be helpful in some situations. If you specify the record 2eyword, T!"# $ will generate another type of SQL script in addition to the regular report. This SQL script will contain a copy of each SQL statement issued by the application while tracing was enabled. 7ou could get this same information from the T!"# $ report itself, but this way could save some cutting and pasting. The sort 2eyword is extremely useful. Typically, a T!"# $ report may include hundreds of SQL statements, but you may only be interested in a few resource intensive queries. The sort 2eyword allows you to order the listing of the SQL statements so that you don9t have to scan the entire file loo2ing for resource hogs. In some ways, the sort feature is too powerful for its own good. $or example, you cannot sort statements by '"1 time consumedPinstead you sort by '"1 time spent parsing, '"1 time spent executing, or '"1 time spent fetching. Sample TKPROF
TKPR .K Relea/e LA#AMA#A0 - P459u01:52 52 Sa1 0# Ma4 2003 (0) C5py4:N81 #LLL 4:N81/ 4e/e4Oe9A 4a0le C54p54a1:52A All

T4a0e 3:leK A!CA140 S541 5p1:52/K 9e3aul1 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@ 05u21 ; 2um>e4 53 1:me/ CI p450e9u4e 7a/ eDe0u1e9 0pu ; 0pu 1:me :2 /e0529/ eDe0u1:2N elap/e9 ; elap/e9 1:me :2 /e0529/ eDe0u1:2N 9:/B ; 2um>e4 53 p8y/:0al 4ea9/ 53 >u33e4/ 345m 9:/B Cue4y ; 2um>e4 53 >u33e4/ N511e2 354 052/:/1e21 4ea9 0u44e21 ; 2um>e4 53 >u33e4/ N511e2 :2 0u44e21 m59e (u/ually 354 up9a1e) 457/ ; 2um>e4 53 457/ p450e//e9 >y 18e 3e108 54 eDe0u1e 0all @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@

A)TER SESSI N SET /Cl_14a0e ; TR%E 0all 05u21 0pu elap/e9 9:/B Cue4y 0u44e21 457/ ------- ------ -------- ---------- ------------------- ---------- ---------Pa4/e 0 0A00 0A00 0 0 0 0 EDe0u1e # 0A00 0A00 0 0 0 0 .e108 0 0A00 0A00 0 0 0 0 ------- ------ -------- ---------- ------------------- ---------- ---------151al # 0A00 0A00 0 0 0 0 M://e/ :2 l:>4a4y 0a08e 9u4:2N pa4/eK 0 M://e/ :2 l:>4a4y 0a08e 9u4:2N eDe0u1eK # p1:m:Pe4 N5alK CH SE Pa4/:2N u/e4 :9K 60 (A!CD)

Inte"p"etation O& E'ecution PLan


&n execution plan is a hierarchical structure somewhat li2e an inverted tree. The SQL statement being examined can be thought of as the root of the tree. This will be the first line on an execution plan listing, the line that is least indented. This statement can be thought of as the result of one or more subordinate operations. (ach of these subordinate operations can possibly be decomposed further. This decomposition process continues repeatedly until eventually even the most complex SQL statement is bro2en down into a set of basic data access operations. 'onsider the following simple query and execution plan@
SE)ECT 9epa41me21_:9= 9epa41me21_2um>e4= 9epa41me21_2ame .R M 9epa41me21/ $HERE %PPER (9epa41me21_2ame) )IKE QACMERQ RDER !& 9epa41me21_2ame< ID PARENT PERATI N !"ECT_NAME ---- ------ ---------------------------------------------------------------0 SE)ECT STATEMENT # 0 S RT RDER !& 2 # TA!)E ACCESS .%)) DEPARTMENTS

The root operationPthat which we explainedPis a S(L('T statement. The output of the statement will be the results of a sort operation %for the purposes of satisfying the #3(# 47 clause). The input to the sort will be the results of a full table scan of the departments table. Stated more clearly, the database server will execute this query by chec2ing every row in the departments table for a criteria match and sorting the results. "erhaps the developer expected racle to use an index on the department8name column to avoid a full table scan, but the use of the 1""(# function defeated the index. %& function/based index could be deployed to ma2e this query more efficient.) 'onsider the following query and execution plan@
SE)ECT aA9epa41me21_2ame= >A:2O5:0e_2um>e4= >A:2O5:0e_9a1e .R M 9epa41me21/ a= :2O5:0e/ > $HERE >A:2O5:0e_9a1e , TR%NC (S&SDATE - #) AND aA9epa41me21_:9 ; >A9epa41me21_:9< ID PARENT PERATI N !"ECT_NAME ---- ------ ---------------------------------------------------------------0 SE)ECT STATEMENT # 0 NESTED ) PS 2 # TA!)E ACCESS !& INDE- R $ID INV ICES 3 2 INDE- RAN*E SCAN INV ICES_DATE 6 # TA!)E ACCESS !& INDE- R $ID DEPARTMENTS ( 6 INDE- %NI+%E SCAN DEPARTMENTS_PK

&gain, the root operation is a S(L('T statement. This time, the S(L('T statement gets its input from the results of a nested loops .oin operation. The nested loops operation ta2es as input the results of accesses to the invoices and departments tables. %7ou can tell from the indenting that accesses to both tables feed directly into the nested loops operation.) The invoices table is accessed by a range scan of the invoices8date index, while the departments table is accessed by a unique scan of the departments8p2 index. In plainer language, here is how racle will execute this query@ racle will perform a range scan on the invoices8date index to find the # 6I3s of all rows in the invoices table that have an invoice date matching the query criteria. $or each # 6I3 found, racle will fetch the corresponding row from the invoices table, loo2 up the department8id from the invoices record in the departments8p2 index, and use the # 6I3 found in the departments8p2 index entry to fetch the correct department record. This, in effect, .oins the rows fetched from the invoices table with their corresponding matches in the departments table. The results of the nested loops .oin operation are returned as the query results. 'onsider the following query and execution plan@

SE)ECT aA9epa41me21_2ame= C %NT (DISTINCT >A:2O5:0e_:9) S pe2 I2O5:0e/S= C %NT (0A:2O5:0e_:9) S pe2 I2O5:0e I1em/S .R M 9epa41me21/ a= :2O5:0e/ >= :2O5:0e_:1em/ 0 $HERE >A:2O5:0e_/1a1u/ ; Q PENQ AND aA9epa41me21_:9 ; >A9epa41me21_:9 AND 0A:2O5:0e_:9 (T) ; >A:2O5:0e_:9 *R %P !& aA9epa41me21_2ame< ID PARENT PERATI N !"ECT_NAME ---- ------ ---------------------------------------------------------------0 SE)ECT STATEMENT # 0 S RT *R %P !& 2 # NESTED ) PS %TER 3 2 HASH " IN 6 3 TA!)E ACCESS !& INDE- R $ID INV ICES ( 6 INDE- RAN*E SCAN INV ICES_STAT%S M 3 TA!)E ACCESS .%)) DEPARTMENTS U 2 INDE- RAN*E SCAN INV ICE_ITEMS_PK

This execution plan is more complex than the previous two, and here you can start to get a feel for the way in which complex operations get bro2en down into simpler subordinate operations. To execute this query, the database server will do the following@ $irst racle will perform a range scan on the invoices8status index to get the # 6I3s of all rows in the invoices table with the desired status. $or each # 6I3 found, the record from the invoices table will be fetched. This set of invoice records will be set aside for a moment while the focus turns to the departments table. :ere, racle will fetch all departments records with a full table scan. To perform a hash .oin between the invoices and departments tables, racle will build a hash from the department records and use the invoice records to probe the department hash. +ext, a nested loops .oin will be performed between the results of the hash .oin and the invoice8items8p2 index. $or each row resulting from the hash .oin, racle will perform a unique scan of the invoice8items8p2 index to find index entries for matching invoice items. +ote that racle gets everything it needs from the index and doesn9t even need to access the invoice8items table at all. &lso note that the nested loops operation is an outer .oin. & sort operation for the purposes of grouping is performed on the results of the nested loops operation in order to complete the S(L('T statement. It is interesting to note that racle chose to use a hash .oin and a full table scan on the departments table instead of the more traditional nested loops .oin. In this database there are many invoices and a relatively small number of departments, ma2ing a full table scan of the departments table less expensive than repeated index loo2ups on the departments8p2 index. 4ut suppose the departments table was enormous and the relative

number of invoices was quite small. In that scenario a nested loops .oin might be better than a hash .oin. (xamining the execution plan allows you to see which .oin method racle is using. 7ou could then apply optimi,er hints to coerce racle to use alternate methods and compare the performance. 7ou may wonder how I got that whole detailed explanation out of the eight line execution plan listing shown above. 3id I read anything into the execution planR +oO It9s all thereO 1nderstanding the standard inputs and outputs of each type of operation and coupling this with the indenting is 2ey to reading an execution plan. & nested loops .oin operation always ta2es two inputs@ $or every row coming from the first input, the second input is executed once to find matching rows. & hash .oin operation also ta2es two inputs@ The second input is read completely once and used to build a hash. $or each row coming from the first input, one probe is performed against this hash. Sorting operations, meanwhile, ta2e in one input. 6hen the entire input has been read, the rows are sorted and output in the desired order. +ow let9s loo2 at a query with a more complicated execution plan@
SE)ECT .R M $HERE 9epa41me21_2ame 9epa41me21/ a E-ISTS ( SE)ECT # .R M :2O5:0e/_O:e7 > $HERE >A9epa41me21_:9 ; aA9epa41me21_:9 AND 2um>e4_53_l:2e/ , #00 ) RDER !& 9epa41me21_2ame<

ID PARENT PERATI N !"ECT_NAME ---- ------ ---------------------------------------------------------------0 SE)ECT STATEMENT # 0 S RT RDER !& 2 # .I)TER 3 2 TA!)E ACCESS .%)) DEPARTMENTS 6 2 VIE$ INV ICES_VIE$ ( 6 .I)TER M ( S RT *R %P !& U M NESTED ) PS 8 U TA!)E ACCESS !& INDE- R $ID INV ICES L 8 INDE- RAN*E SCAN INV ICES_DEPARTMENT_ID #0 U INDE- RAN*E SCAN INV ICE_ITEMS_PK

This execution plan is somewhat complex because the query includes a subquery that the optimi,er could not rewrite as a simple .oin, and a view whose definition could not be merged into the query. The definition of the invoices8view view is as follows@
CREATE R REP)ACE VIE$ :2O5:0e/_O:e7 AS SE)ECT aA:2O5:0e_:9= aA9epa41me21_:9= aA:2O5:0e_9a1e= aA:2O5:0e_/1a1u/= aA:2O5:0e_2um>e4= aA:2O5:0e_1ype= aA151al_am5u21= C %NT(@) 2um>e4_53_l:2e/ .R M :2O5:0e/ a= :2O5:0e_:1em/ > $HERE >A:2O5:0e_:9 ; aA:2O5:0e_:9 *R %P !& aA:2O5:0e_:9= aA9epa41me21_:9= aA:2O5:0e_9a1e= aA:2O5:0e_/1a1u/= aA:2O5:0e_2um>e4= aA:2O5:0e_1ype= aA151al_am5u21<

:ere is what this execution plan says@ racle will execute this query by reading all rows from the departments table with a full table scan. $or each department record, the invoices8view view will be assembled as a filter and the relevant contents of the view will be examined to determine whether the department should be part of the result set or not. racle will assemble the view by performing an index range scan on the invoices8department8id index and fetching the rows from the invoices table containing one specific department8id. $or each invoice record found, the invoice8items8p2 index will be range scanned to get a nested loops .oin of invoices to their invoice8items records. The results of the .oin are sorted for grouping, and then groups with =<< or fewer invoice8items records are filtered out. 6hat is left at the step with I3 E is a list of invoices for one specific department that have more than =<< invoice8items records associated. If at least one such invoice exists, then the department passes the filter at the step with I3 F. $inally, all department records passing this filter are sorted for correct ordering and the results are complete. +ote that queries involving simple views will not result in a ;viewA operation in the execution plan. This is because racle can often merge a view definition into the query referencing the view so that the table accesses required to implement the view .ust become part of the regular execution plan. In this example, the C# 1" 47 clause embedded in the view foiled racle9s ability to merge the view into the query, ma2ing a separate ;viewA operation necessary in order to execute the query. &lso note that the filter operation can ta2e on a few different forms. In general, a filter operation is where racle loo2s at a set of candidate rows and eliminates some based on certain criteria. This criteria could involve a simple test such as number8of8lines S =<< or it could be an elaborate subquery. In this example, the filter at step I3 G ta2es only one input. :ere racle evaluates each row from the input one at a time and either adds the row to the output or discards it as

appropriate. 0eanwhile, the filter at step I3 F ta2es two inputs. 6hen a filter ta2es two inputs, racle reads the rows from the first input one at a time and executes the second input once for each row. 4ased on the results of the second input, the row from the first input is either added to the output or discarded. racle is able to perform simple filtering operations while performing a full table scan. Therefore, a separate filter operation will not appear in the execution plan when racle performs a full table scan and throws out rows that don9t satisfy a 6:(#( clause. $ilter operations with one input commonly appear in queries with view operations or :&TI+C clauses, while filter operations with multiple inputs will appear in queries with (*ISTS clauses. &n important note about execution plans and subqueries@ 6hen a SQL statement involves subqueries, racle tries to merge the subquery into the main statement by using a .oin. If this is not feasible and the subquery does not have any dependencies or references to the main query, then racle will treat the subquery as a completely separate statement from the standpoint of developing an execution planPalmost as if two separate SQL statements were sent to the database server. 6hen you generate an execution plan for a statement that includes a fully autonomous subquery, the execution plan may not include the operations for the subquery. In this situation, you need to generate an execution plan for the subquery separately.

Inte"p"etation O& TKPROF


The information displayed in a T!"# $ report can be extremely valuable in the application tuning process. f course the execution plan listing will give you insights into how racle executes the SQL statements that ma2e up the application, and ways to potentially improve performance. :owever, the other elements of the T!"# $ report can be helpful as well. $rom the counts of parse, execute, and fetch calls, you can see if applications are ma2ing appropriate use of racle9s &"Is. Is the application fetching rows one at a timeR Is the application reparsing the same cursor thousands of times instead of holding it open and avoiding subsequent parsesR Is the application submitting large numbers of simple SQL statements instead of bul2ing them into "L-SQL bloc2s or perhaps using array bindsR Loo2ing at the '"1 and I- statistics, you can see which statements consume the most system resources. 'ould some statements be tuned so as to be less '"1 intensive or less I- intensiveR 6ould shaving .ust a few buffer gets off of a statement9s execution plan have a big impact because the statement gets executed so frequentlyR The row counts on the individual operations in an execution plan display can help identify inefficiencies. &re tables being .oined in the wrong order, causing large numbers of rows to be .oined and eliminated only at the very endR &re large numbers of duplicate rows being fed into sorts for uniqueness when perhaps the duplicates could have been weeded out earlier onR

T!"# $ reports may seem long and complicated, but nothing in the report is without purpose. %6ell, o2ay, the row source operation listing sometimes isn9t very usefulO) 7ou can learn volumes about how your application interacts with the database server by generating and reading a T!"# $ report. T!"# $ report starts with a header that lists the T!"# $ version, the date and time the report was generated, the name of the trace file, the sort option used, and a brief definition of the column headings in the report. (very report ends with a series of summary statistics. 7ou can see the heading and summary statistics on the sample T!"# $ report shown earlier in this paper. The main body of the T!"# $ report consists of one entry for each distinct SQL statement that was executed by the database server while SQL trace was enabled. There are a few subtleties at play in the previous sentence. If an application queries the departments table G< times, each time specifying a different department8id as a literal, then there will be G< separate entries in the T!"# $ report. If however, the application specifies the department8id as a bind variable, then there will be only one entry in the report with an indication that the statement was executed G< times. $urthermore, the report will also include SQL statements initiated by the database server itself in order to perform so/called ;recursive operationsA such as manage the data dictionary and dictionary cache. The entries for each SQL statement in the T!"# $ report are separated by a row of asteris2s. The first part of each entry lists the SQL statement and statistics pertaining to the parsing, execution, and fetching of the SQL statement. 'onsider the following example@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ SE)ECT 1a>le_2ame .R M u/e4_1a>le/ RDER !& 1a>le_2ame 0all 05u21 0pu elap/e9 9:/B Cue4y 0u44e21 457/ ------- ------ -------- ---------- ------------------- ---------- ---------Pa4/e # 0A0# 0A02 0 0 0 0 EDe0u1e # 0A00 0A00 0 0 0 0 .e108 #6 0A(L 0ALL 0 33M33 0 #L6 ------- ------ -------- ---------- ------------------- ---------- ---------151al #M 0AM0 #A0# 0 33M33 0 #L6 M://e/ :2 l:>4a4y 0a08e 9u4:2N pa4/eK # p1:m:Pe4 N5alK CH SE

Pa4/:2N u/e4 :9K RSCHRA*

H4e0u4/:Oe 9ep18K 0J

This may not seem li2e a useful example because it is simply a query against a dictionary view and does not involve application tables. :owever, this query actually serves the purpose well from the standpoint of highlighting the elements of a T!"# $ report. #eading across, we see that while SQL trace was enabled, the application called on the database server to parse this statement once. <.<= '"1 seconds over a period of <.<F elapsed seconds were used on the parse call, although no physical dis2 I- s or even any buffer gets were required. %6e can infer that all dictionary data required to parse the statement were already in the dictionary cache in the SC&.) The next line shows that the application called on racle to execute the query once, with less than <.<= seconds of '"1 time and elapsed time being used on the execute call. &gain, no physical dis2 I- s or buffer gets were required. The fact that almost no resources were used on the execute call might seem strange, but it ma2es perfect sense when you consider that racle defers all wor2 on most S(L('T statements until the first row is fetched. The next line indicates that the application performed =E fetch calls, retrieving a total of =?E rows. The =E calls used a total of <.G? '"1 seconds and <.?? seconds of elapsed time. &lthough no physical dis2 I- s were performed, >>,N>> buffers were gotten in consistent mode %consistent gets). In other words, there were >>,N>> hits in the buffer cache and no misses. I ran this query from SQLB"lus, and we can see here that SQLB"lus uses an array interface to fetch multiple rows on one fetch call. 6e can also see that, although no dis2 I- s were necessary, it too2 quite a bit of processing to complete this query. The remaining lines on the first part of the entry for this SQL statement show that there was a miss in the library cache %the SQL statement was not already in the shared pool), the ': S( optimi,er goal was used to develop the execution plan, and the parsing was performed in the #S':#&C schema. +otice the text in square brac2ets concerning recursive depth. This did not actually appear on the reportPI added it for effect. The fact that the report did not mention recursive depth for this statement indicates that it was executed at the top level. In other words, the application issued this statement directly to the database server. 6hen recursion is involved, the T!"# $ report will indicate the depth of the recursion next to the parsing user. There are two primary ways in which recursion occurs. 3ata dictionary operations can cause recursive SQL operations. 6hen a query references a schema ob.ect that is missing from the dictionary cache, a recursive query is executed in order to fetch the ob.ect definition into the dictionary cache. $or example, a query from a view whose definition is not in the dictionary cache will cause a recursive query against viewD to be parsed in the S7S schema. &lso, dynamic space allocations in dictionary/managed tablespaces will cause recursive updates against uetD and fetD in the S7S schema.

1se of database triggers and stored procedures can also cause recursion. Suppose an application inserts a row into a table that has a database trigger. 6hen the trigger fires, its statements run at a recursion depth of one. If the trigger invo2es a stored procedure, the recursion depth could increase to two. This could continue through any number of levels. So far we have been loo2ing at the top part of the SQL statement entry in the T!"# $ report. The remainder of the entry consists of a row source operation list and optionally an execution plan display. %If the explain 2eyword was not used when the T!"# $ report was generated, then the execution plan display will be omitted.) 'onsider the following example, which is the rest of the entry shown above@
R57/ R57 S5u40e pe4a1:52 --------------------------------------------------------#L6 S RT RDER !& #L6 NESTED ) PS #L( NESTED ) PS %TER #L( NESTED ) PS %TER #L( NESTED ) PS ###6M TA!)E ACCESS !& INDE- R $ID !"V ###6M INDE- RAN*E SCAN (5>?e01 :9 36) ##33L TA!)E ACCESS C)%STER TA!V #2MM( INDE- %NI+%E SCAN (5>?e01 :9 3) 33 INDE- %NI+%E SCAN (5>?e01 :9 33) #L3 TA!)E ACCESS C)%STER SE*V 38U INDE- %NI+%E SCAN (5>?e01 :9 L) #L6 TA!)E ACCESS C)%STER TSV 388 INDE- %NI+%E SCAN (5>?e01 :9 U) R57/ EDe0u1:52 Pla2 --------------------------------------------------------0 SE)ECT STATEMENT * A)K CH SE #L6 S RT ( RDER !&) #L6 NESTED ) PS #L( NESTED ) PS ( %TER) #L( NESTED ) PS ( %TER) #L( NESTED ) PS ###6M TA!)E ACCESS (!& INDE- R $ID) . Q !"VQ ###6M INDE- (RAN*E SCAN) . QI_ !"2Q (%NI+%E) ##33L TA!)E ACCESS (C)%STER) . QTA!VQ #2MM( INDE- (%NI+%E SCAN) . QI_ !"GQ (N N%NI+%E) 33 INDE- (%NI+%E SCAN) . QI_ !"#Q (%NI+%E) #L3 TA!)E ACCESS (C)%STER) . QSE*VQ 38U INDE- (%NI+%E SCAN) . QI_.I)EG_!) CKGQ (N N-%NI+%E) #L6 TA!)E ACCESS (C)%STER) . QTSVQ 388 INDE- (%NI+%E SCAN) . QI_TSGQ (N N-%NI+%E)

The row source operation listing loo2s very much li2e an execution plan. It is based on data collected from the SQL trace file and can be thought of as a ;poor man9s execution planA. It is close, but not complete. The execution plan shows the same basic information you could get from the autotrace facility of SQLB"lus or by querying the plan table after an (*"L&I+ "L&+ statementP with one 2ey difference. The rows column along the left side of the execution plan contains a count of how many rows of data racle processed at each step during the execution of the statement. This is not an estimate from the optimi,er, but rather actual counts based on the contents of the SQL trace file. &lthough the query in this example goes against a dictionary view and is not terribly interesting, you can see that racle did a lot of wor2 to get the =?E rows in the result@ ==,=EN range scans were performed against the i8ob.F index, followed by ==,=EN accesses on the ob.D table. This led to =F,NNG non/unique loo2ups on the i8ob.U index, ==,>>? accesses on the tabD table, and so on. In situations where it is feasible to actually execute the SQL statement you wish to explain %as opposed to merely parsing it as with the (*"L&I+ "L&+ statement), I believe T!"# $ offers the best execution plan display. C1I tools such as T &3 will give you results with much less effort, but the display you get from T &3 is not =<<L complete and in certain situations critical information is missing. %&gain, my experience is with the free versionO) 0eanwhile, simple plan table query scripts li2e my explain.sql presented earlier in this paper or utlxpls.sql display very incomplete information. T!"# $ gives the most relevant detail, and the actual row counts on each operation can be very useful in diagnosing performance problems. &utotrace in SQLB"lus gives you most of the information and is easy to use, so I give it a close second place.

$onclu!ion
In this paper we tried to address the queries li2e@ 6hen is a nested loops .oin better than a hash .oinR In which order should tables be .oinedR These are all questions without universal answers. In reality, there are many factors that contribute to determining which .oin method is better or which .oin order is optimal. $inally, there are both good and poor ways to code SQL statements. :ere are some guidelines for SQL statement coding that will help both the rule/based and the cost/based optimi,ers@

DON'T use calculations in the 78e4e clause on indexed columns unless the intended behavior is to disable the index; any function on indexed columns will ignore the index.

DO use the IN operator instead of N T. Try to avoid using the N T command by using > ! " ! etc.

DON'T use an index if more than #$% of the rows will be returned by the &uery.

DO use array processing whenever possible '(xport and )ro*+ applications,. DON'T use sub&ueries if other solutions exist ')-./0- loop! for example,. DO use hints to ensure the desired execution1plan results. DON'T write applications that use /0- execution1plan defaults. Oracle ma2es no guarantees that default behavior will be maintained in future releases! or even between different hardware platforms.

Vous aimerez peut-être aussi