< previous page page_288 next page > < previous page page_289 next page > Page 289 The SHOW_PLAN script also returns the overall cost of executing the query. In this example, the cost is 21. This number has no meaning in an absolute sense. It's simply a scoring mechanism used by the optimizer to facilitate choosing one plan from many possibilities. You should use it only when comparing two execution plans to see which is more efficient. A plan with a cost of 21, for example, would be approximately twice as efficient as a plan with a cost of 42. If you are using the rule-based optimizer, the cost will be null. Oracle will use the rule- based optimizer if you have not used the ANALYZE TABLE command to gather statistics for any of the tables involved in the query. Making sense of the results The key to interpreting an execution plan is to understand that the display is hierarchical. A step may consist of one or more child steps, and these child steps are shown indented underneath their parent. Executing any given step involves executing all its children, so to understand the plan, you pretty much have to work your way out from the innermost step. In this example, there are three major steps to the plan. First, Oracle will join the PROJECT and PROJECT_HOURS tables, using a hash join method. Next, the results of this join will be joined with the EMPLOYEE table, also using a hash join method. Finally, the results are sorted on the GROUP BY columns. After the sort, the rows are returned as the result of the SELECT statement. Table 8-1 gives a brief description of the various operations, together with their options, that you may see when querying the plan table. For more detailed information about any of these operations, refer to the Oracle8 Server Tuning manual. Table 8-1. EXPLAIN PLAN Operations Operation Options Description AND-EQUAL This step will have two or more child steps, each of which returns a set of ROWIDs. The AND-EQUAL operation selects only those ROWIDs that are returned by all the child operations. BITMAP CONVERSION TO ROWIDS Converts a bitmap from a bitmap index to a set of ROWIDs that can be used to retrieve the actual data. CONVERSION FROM ROWIDS Converts a set of ROWIDs into a bitmapped representation. CONVERSION COUNT Counts the number of rows represented by a bitmap. (table continued on next page) < previous page page_289 next page > < previous page page_290 next page > Page 290 Table 8-1 EXPLAIN PLAN Operations(continued) Operation Options Description INDEX SINGLE VALUE Retrieves the bitmap for a single key value. For example, if the field was a YES/NO field, and your query wanted only rows with a value of YES, then this operation would be used. INDEX RANGE SCAN Similar to BITMAP INDEX SINGLE VALUE, but bitmaps are returned for a range of key values. INDEX FULL SCAN The entire bitmap index will be scanned. MERGE Merges two bitmaps together, and returns one bitmap as a result. This is an OR operation between two bitmaps. The resulting bitmap will select all rows from the first bitmap plus all rows from the second bitmap. MINUS This is the opposite of a MERGE, and may have two or three child operations that return bitmaps. The bitmap returned by the first child operation is used as a starting point. All rows represented by the second bitmap are subtracted from the first. If the column is nullable, then all rows with null values are also subtracted. OR Takes two bitmaps as input, ORs them together, and returns one bitmap as a result. The returned bitmap will select all rows from the first plus all rows from the second. CONNECT BY Rows are being retrieved hierarchially because the query was written with a CONNECT BY clause. CONCATENATION Multiple sets of rows are combined into one set, essentially a UNION ALL. COUNT Counts the number of rows that have been selected from a table. STOPKEY The number of rows to be counted is limited by the use of ROWNUM in the query's WHERE clause. FILTER Takes a set of rows as input, and eliminates some of them based on a condition from the query's WHERE clause. FIRST ROW Retrieves only the first row of query's result set. FOR UPDATE Locks rows that are retrieved. This would be the result of specifying FOR UPDATE in the original query. HASH JOIN Joins two tables using a hash join method. (table continued on next page) < previous page page_290 next page > < previous page page_291 next page > Page 291 Table 8-1. EXPLAIN Operations(continued) Operation Options Description INDEX UNIQUE The lookup of a unique value from an index. You would see this only when the index is a unique index, such as those used to enforce a primary key or a unique key. RANGE SCAN An index is being scanned for rows that fall into a range of values. The index is scanned in ascending order. RANGE SCAN DESCENDING Same as RANGE SCAN, but the index is scanned in descending order. INLIST ITERATOR One or more operations are to be performed once for each value in an IN predicate. INTERSECTION Two rowsets are taken as input, and only rows that appear in both sets are returned. MERGE JOIN Joins two rowsets based on some common value. Both rowsets will first have been sorted by this value. This is an inner join. OUTER Similar to a MERGE JOIN, but an outer join is performed. ANTI Indicates that an anti-join is being performed. SEMI Indicates that a semi-join is being performed. MINUS This is the result of the MINUS operator. Two rowsets are taken as inputs. The resulting rowset contains all rows from the first input that do not appear in the second input. NESTED LOOPS This operation will have two children, each returning a rowset. For every row returned by the first child, the second child operation will be executed. OUTER Represents a nested loop used to perform an outer join. PARTITION Executes an operation for one or more partitions. The PARTITION_START and PARTITION_STOP columns give the range of partitions over which the operation is performed. SINGLE The operation will be performed on a single partition. ITERATOR The operation will be performed on several partitions. ALL The operation will be performed on all partitions. INLIST The operation will be performed on the partitions, and is being driven by an IN predicate. (table continued on next page) < previous page page_291 next page > < previous page page_292 next page > Page 292 Table 8-1. EXPLAIN PLAN Operations (continued) Operation Options Description PROJECTION Takes multiple queries as input, and returns a single set of records. This is used with INTERSECTION, MINUS, and UNION operations. REMOTE Indicates that a rowset is being returned from a remote database. SEQUENCE An Oracle sequence is being accessed. SORT AGGREGATE Applies a group function, such as COUNT, to a rowset, and returns only one row as the result. UNIQUE Sorts a rowset and eliminates duplicates. GROUP BY Sorts a rowset into groups. This is the result of a GROUP BY clause. JOIN Sorts a rowset in preparation for a join. See MERGE JOIN. ORDER BY Sorts a rowset in accordance with the ORDER BY clause specified in the query. TABLE ACCESS FULL Oracle will read all rows in the specified table. CLUSTER Oracle will read all rows in a table that match a specified index cluster key. HASH Oracle will read all rows in a table that match a specified hash cluster key. BY ROWID Oracle will retrieve a row from a table based on its ROWID. UNION Takes two rowsets, eliminates duplicates, and returns the result as one set. VIEW Executes the query behind a view and returns the resulting rowset. Using AUTOTRACE Beginning with version 3.3 of SQL*Plus, Oracle provides a setting that automatically displays the execution plan for any query you execute. The name of this setting is AUTOTRACE, and you can turn it off and on with the SET command. There is one big catch. The query must actually be executed before you can see the results. If you are contemplating a query against a large table, it might take all day for a poorly-tuned query to execute. In that case, you might just want to see the execution plan before you run the query, not afterwards. You may also not want this behavior if you are writing a DELETE or an UPDATE statement, because you would need to actually delete or update some data in order to see the execution plan. < previous page page_292 next page > < previous page page_293 next page > Page 293 Before you can use AUTOTRACE to display execution plans, you must have created a plan table. AUTOTRACE uses this table, and expects the name to be PLAN_TABLE, which is the default name if you use the UTLXPLAN.SQL script to create it. Granting Access to the Performance Views AUTOTRACE will do more than just display the execution plan for a query. It also displays statistics that show you how much disk I/O and network traffic occurred during a query's execution. Other information, such as the number of sorts performed on the data, is given as well. In order to see the statistical data AUTOTRACE returns, you must have SELECT access to certain of Oracle's dynamic performance views. Dynamic performance views, whose names usually begin with V$ or V_$, are pseudoviews, maintained by Oracle, that contain real-time performance information. With Oracle8, version 8.0.3, you need SELECT access to the following three tables: v_$sesstat v_$statname v_$session Since the specific tables to which you need access may vary from one version of Oracle to the next, Oracle provides a script your DBA can run to simplify the process of granting the needed access to users of AUTOTRACE. The script name is PLUSTRCE.SQL, and it is stored in the PLUS directory under the Oracle home directory. The script must be executed while logged in as user SYS, and it creates a role named PLUSTRACE that has the needed privileges to use AUTOTRACE from SQL*plus. Usually, only database administrators can log in as SYS. Here's how to run the script: SQL> CONNECT sys/mgr Connected. SQL> @c:\orawin95\plus80\plustrce.sql SQL> SQL> drop role plustrace; Role dropped. SQL> create role plustrace; Role created. SQL> SQL> grant select on v_$sesstat to plustrace; < previous page page_293 next page > < previous page page_294 next page > Page 294 Grant succeeded. SQL> grant select on v_$statname to plustrace; Grant succeeded. SQL> grant select on v_$session to plustrace; Grant succeeded. SQL> grant plustrace to dba with admin option; Grant succeeded. SQL> SQL> set echo off Once the script has been run, the PLUSTRACE role will exist. PLUSTRACE should be granted to any user who needs to use AUTOTRACE; for example: SQL> GRANT plustrace TO SARAH; Grant succeeded. Now the user SARAH will be able to execute the SET AUTOTRACE ON command from SQL*Plus. Executing a Query with AUTOTRACE On There are several options you can use with SET AUTOTRACE. By default, when you turn AUTOTRACE on, SQL*Plus will show both the execution plan and some execution statistics for any query you execute. You can, if you like, limit AUTOTRACE to showing only the execution plan or only the execution statistics. If you don't have the PLUSTRACE role, or don't otherwise have access to the required dynamic performance tables, you can issue the command SET AUTOTRACE ON EXPLAIN. This option is discussed later in this section; it limits the display to only the execution plan, and does not require access to the performance tables. You also have the option of suppressing the output from the query you are executing. This is helpful if the query returns a large amount of data, because you aren't forced to watch all the results scroll by before the execution plan is displayed. You'll see how to do this later in this section. < previous page page_294 next page > < previous page page_295 next page > Page 295 Showing Statistics and the plan To enable AUTOTRACE and set it to show both the execution plan and the execution statistics, execute the following command from SQL*Plus: SET AUTOTRACE ON Now execute any query. You will see the query results, followed by the execution plan, followed by the execution statistics. Here is an example: SQL> SET AUTOTRACE ON SQL> SELECT employee_name, SUM(hours_logged) 2 FROM employee, project_hours 3 WHERE employee.employee_id = project_hours.employee_id 4 GROUP BY employee_name; EMPLOYEE_NAME SUM (HOURS_LOGGED) Bohdan Khmelnytsky 116 Hermon Goche 36 Horace Walker 68 Ivan Mazepa 57 Jacob Marley 80 Jeff Gennick 36 Jenny Gennick 49 Jonathan Gennick 116 Pavlo Chubynsky 112 Tarasa Shevchenko 116 10 rows selected. Execution plan 0 SELECT STATEMENT optimizer=CHOOSE 1 0 SORT (GROUP BY) 2 1 NESTED LOOPS 3 2 TABLE ACCESS (FULL) OF PROJECT_HOURS 4 2 TABLE ACCESS (BY INDEX ROWID) OF EMPLOYEE 5 4 INDEX (UNIQUE SCAN) OF EMPLOYEE_PK (UNIQUE) Statistics 0 recursive calls 3 db block gets 210 consista gets 0 physical reads 0 redo size 903 bytes received via SQL*Net to client 777 bytes received via SQL*Net from client 4 SQL*Net roundtrips to/form client 2 sorts (memory) 0 sprts (disk) 10 rows processed < previous page page_295 next page > < previous page page_296 next page > Page 296 One key statistic to look at would be the number of physical reads, particularly in relation to the number of rows processed. The fewer reads per row processed, the better. In the above example, all the data happened to be in memory as a result of previous queries, so no physical reads occurred. The execution plan displayed by AUTOTRACE is formatted just a bit differently from previous plans shown in this chapter. The two leading numeric columns are the ID (of the step) and the PARENT_ID (ID of the parent step) columns. Showing just the plan SQL*Plus allows you to turn AUTOTRACE on with an option to show only the execution plan. This is handy if you do not happen to have the needed privileges to access the execution statistics. Issue the following command from SQL*Plus: SET AUTOTRACE ON EXPLAIN Now, when you issue a SQL statement, only the execution plan is displayed, not the statistics. Here's an example: SQL> SET AUTOTRACE ON EXPLAIN SQL> SELECT employee_name, SUM (hours_logged) 2 FROM employee, project_hours 3 WHERE employee.employee_id = project_hours.employee_id 4 GROUP BY employee_name; EMPLOYEE_NAME SUM(HOURS_LOGGED) Bohdan khmelnysky 116 Hermon Goche 36 Horace Walker 68 Ivan Mazepa 57 Jacob Marley 80 Jeff Gennick 36 Jenny Gennick 49 Jonathan Gennick 116 Pavlo Chubynsky 112 Taras Shevchenko 116 10 rows selected. Execution Plan 0 SELECT STATEMENT Optimizer=CHOOSE 1 0 SORT (GROUP BY) 2 1 NESTED LOOPS 3 2 TABLE ACCESS (FULL) OF PROJECT_HOURS 4 2 TABLE ACCESS (BY INDEX ROWID) OF EMPLOYEE 5 4 INDEX (UNIQUE SCAN) OF EMPLOYEE_PK (UNIQUE) < previous page page_296 next page > < previous page page_297 next page > Page 297 Suppressing the query output With AUTOTRACE, you also have the option of suppressing the output from any queries you run. This saves you from having to wait for the results to scroll by before you see the execution plan and statistics. To turn AUTOTRACE on and suppress any query output, issue the following command: SET AUTOTRACE TRACEONLY The EXPLAIN option is still valid, so if you only want to see the execution plan, issue the command like this: SET AUTOTRACE TRACEONLY EXPLAIN Now, execute a query, and you will see only the execution plan, not the data: SQL> SET AUTOTRACE TRACEONLY EXPLAIN SQL> SELECT employee_name, SUM(hours_logged) 2 FROM employee, project_hours 3 WHERE employee.employee_id = project_hours.employee_id 4 GROUP BY employee_name; Execution plan 0 SELECT STATEMENT optimizer=CHOOSE 1 0 SORT (GROUP BY) 2 1 NESTED LOOPS 3 2 TABLE ACCESS (FULL) OF PROJECT_HOURS 4 2 TABLE ACCESS (BY INDEX ROWID) OF EMPLOYEE 5 4 INDEX (UNIQUE SCAN) OF EMPLOYEE_PK (UNIQUE) It's important to understand that even when the TRACEONLY option is used, the query is still executed. This is really important to remember if the query in question is a DELETE or UPDATE. Turning AUTOTRACE off When you are done using AUTOTRACE, you can turn it off with the following command: SET AUTOTRACE OFF Improving on EXPLAIN PLAN Results If you don't like the results you get from EXPLAIN PLAN, there are some things you can do to change how Oracle executes your query. Generally speaking, these things fall into the following three categories: Restating the query Creating or modifying indexes Using hints < previous page page_297 next page > . SQL* plus. Usually, only database administrators can log in as SYS. Here's how to run the script: SQL& gt; CONNECT sys/mgr Connected. SQL& gt; @c:orawin95 plus8 0plustrce .sql SQL& gt; SQL& gt;. version of Oracle to the next, Oracle provides a script your DBA can run to simplify the process of granting the needed access to users of AUTOTRACE. The script name is PLUSTRCE .SQL, and it. SQL& gt; SQL& gt; set echo off Once the script has been run, the PLUSTRACE role will exist. PLUSTRACE should be granted to any user who needs to use AUTOTRACE; for example: SQL& gt; GRANT plustrace