Chapter 8. Tuning and Timing

Oracle offers two features that can be used from SQL*Plus to monitor and improve the performance of your scripts and SQL statements. These two features are SQL*Plus timers and the EXPLAIN PLAN command.

SQL*Plus has a timing feature built into it that can be used to monitor the length of time it takes to execute a SQL command, a PL/SQL block, or any other part of a script. To measure the time it takes to execute a SQL statement, you start a timer prior to executing the statement, then display the value of the timer immediately after the statement is executed.

The EXPLAIN PLAN command, although it is a SQL command, not a SQL*Plus command, is often used from SQL*Plus. EXPLAIN PLAN can be used to find out exactly how Oracle intends to execute any given SQL query. It will tell you, for example, whether or not an index will be used, and what the name of that index will be. Once you know how Oracle intends to execute the query, you can use hints to influence or alter Oracle’s default plan based on your knowledge of the data. A hint is a command to the optimizer that is embedded in a comment within a SQL query. The optimizer is the part of Oracle that determines how best to retrieve the data required by a SQL statement.

This chapter is not intended to be an exhaustive reference for tuning SQL statements. Several good books have been written on this subject. What this chapter does provide is a quick overview of the mechanics of tuning and a convenient summary of the hints available to you.

Using SQL*Plus Timers

SQL*Plus has a crude timing facility built into it that allows you to measure the elapsed time of a script or any portion of a script. You can even have SQL*Plus report the elapsed execution time of every SQL query and PL/SQL block automatically after each statement has executed. Timers can be nested so that you can time the overall execution of a script as well as the execution time of each individual statement.

Timer resolution varies with the hardware platform being used. Under Windows NT or 95, the elapsed time is reported in milliseconds. Under HP Unix, it is resolved only to the hundredth of a second, but the display format is much nicer. Here is how an elapsed time of 90.5 seconds will be shown under Windows:

real: 90500

90,500 milliseconds is equivalent to 90.5 seconds. With Unix versions of SQL*Plus, the display is much more user-friendly. Here’s how the HP-UX version of SQL*Plus would report the same value:

Elapsed: 00:01:30.5

Unix uses an hour, minute, second, and hundredths format, so 90.5 seconds is reported as 1 minute, 30 seconds, and 50 hundredths. Remember, the timer is a SQL*Plus timer. The hardware that matters is the machine running the SQL*Plus executable, not the one running the Oracle server.

Timings can be useful in spotting trends. It may be helpful to know, for example, if a script is taking longer and longer to run. Timings can also be helpful in comparing the relative efficiency of two SQL statements. If you have two statements that return equivalent results, and one consistently runs faster than the other, that’s the one you probably want to go with.

Take timing with a grain of salt, though. The timer measures elapsed time, not CPU time, and many factors can throw it off. The network throughput may vary between the execution of two queries. The load on the server could vary as well. For example, one query might run more slowly than another simply because many other users all happened to hit the database at the same time. Be skeptical of once-off results. Look for consistency over several timings.

The SET TIMING Command

You can have SQL*Plus automatically report the elapsed time it takes to execute every query by using the SET TIMING ON command. For example:

SQL> SET TIMING ON

Now, whenever you execute a query, SQL*Plus will report the elapsed time. With the Windows versions of SQL*Plus, this time will be reported in milliseconds. The following example shows that it took 110 milliseconds, or about 1/10 of a second, for a query on DBA_VIEWS to complete:

SQL> SELECT view_name
  2    FROM dba_views
  3   WHERE view_name = 'DBA_TABLES';

VIEW_NAME
------------------------------
DBA_TABLES

 real: 110

Notice that the timing display is rather inelegant. Why a heading of “real” is used, instead of something more descriptive like “elapsed time,” I don’t know.

When timing is on, SQL*Plus will also report the time it takes to execute a PL/SQL block. Here’s an example:

SQL> BEGIN
  2    DBMS_OUTPUT.PUT_LINE('How long does this take?'),
  3  END;
  4  /
How long does this take?

PL/SQL procedure successfully completed.

 real: 270

To turn timing off, simply issue the SET TIMING OFF command as follows:

SQL> SET TIMING OFF

When you have timing turned on, SQL*Plus displays elapsed time only for commands executed by the database server. This includes SQL statements and PL/SQL blocks. Elapsed time for SQL*Plus commands, such as ACCEPT and DEFINE, is not reported.

The TIMING Command

The SQL*Plus TIMING command gives you complete control over when timing starts and stops, and over what is measured. With it, you can turn on a timer at any point in your script. You can display the elapsed time at any point after a timer is turned on, and you can nest timers. Nesting timers gives you a way to time a set of operations, maybe an entire script, while still allowing you to time each individual operation separately.

Tip

The TIMING command is really useful only in scripts. You can use it interactively, but then the elapsed time will include your “think” time and the time it take you to type in commands.

The syntax for the TIMING command looks like this:

TIMI[NG] [START [timer_name ] | SHOW | STOP]

where:

TIMI[NG]

Is the command, which may be abbreviated to TIMI.

START [timer_name]

Starts a new timer, and optionally gives it the name you provide.

SHOW

Shows the current value of the most recently started timer.

STOP

Stops the most recently started timer, shows its current value, then deletes it.

Think of timers as being implemented on a stack. Each time you issue a TIMING START command, you push a new timer onto the stack. The TIMING SHOW and TIMING STOP commands each operate on whatever timer is currently at the top of the stack. To find out how many timers you have currently running, enter the TIMING command with no arguments.

Starting and stopping a timer

Use the TIMING START command to start a timer. If you like, you can give the timer a name, but you don’t have to. Timing starts the moment the command is executed. The following example starts a new timer, and gives it a name of for_testing:

SQL> TIMING START for_testing

You stop the timer and display its final value by issuing the TIMING STOP command as follows:

SQL> TIMING STOP
timing for: for_testing
 real: 56460

In this case, the timer ran for a total elapsed time of 56.460 seconds.

Displaying the value of a timer

You can display the value of a timer without stopping it. This is useful if your script is executing several SQL queries and you want to see the cumulative elapsed time after each one. For example:

SQL> TIMING START for_show
SQL> TIMING SHOW
timing for: for_show
 real: 2250
SQL> TIMING SHOW
timing for: for_show
 real: 3790
SQL> TIMING SHOW
timing for: for_show
 real: 5380
SQL> TIMING SHOW
timing for: for_show
 real: 6920

You can see from this example that once I got going, it took me a tad more than 1 1/2 seconds to type each TIMING SHOW command.

Nesting timers

Timers can be nested, allowing you to time a group of operations, while simultaneously timing each individual operation within the larger group. The following example shows a timer being started, and while that’s running, two more timers are started and stopped. Finally, the first timer is also stopped.

SQL> TIMING START first
SQL> TIMING START second
SQL> TIMING STOP
timing for: second
 real: 2630
SQL> TIMING START third
SQL> TIMING STOP
timing for: third
 real: 2360
SQL> TIMING STOP
timing for: first
 real: 19160

The important thing to notice here is that the first timer kept running during this entire example. The total elapsed time was a bit over 19 seconds, while each of the intermediate operations took a bit over two seconds.

The following example shows how this nesting feature could be used. It runs a script to delete data and reports the elapsed time for each DELETE statement, as well as the total elapsed time for the script as a whole.

SET ECHO ON
TIMING START entire_script

--Delete project hours data and time the operation.
TIMING START delete_project_hours
DELETE FROM project_hours;
TIMING STOP

--Delete project data and time the operation.
TIMING START delete_projects
DELETE FROM project;
TIMING STOP

--Delete employee data and time the operation.
TIMING START
DELETE FROM employee;
TIMING STOP

COMMIT;

--Show the overall elapsed time for the entire script.
TIMING STOP

Here is the output from running the above script:

SQL> TIMING START entire_script
SQL> 
SQL> --Delete project hours data and time the operation.
SQL> TIMING START delete_project_hours
SQL> DELETE FROM project_hours;
SQL> TIMING STOP
timing for: delete_project_hours
 real: 1100
SQL> 
SQL> --Delete project data and time the operation.
SQL> TIMING START delete_projects
SQL> DELETE FROM project;
SQL> TIMING STOP
timing for: delete_projects
 real: 160
SQL> 
SQL> --Delete employee data and time the operation.
SQL> TIMING START
SQL> DELETE FROM employee;
SQL> TIMING STOP
 real: 220
SQL> 
SQL> COMMIT;
SQL> 
SQL> --Show the overall elapsed time for the entire script.
SQL> TIMING STOP
timing for: entire_script
 real: 1750

You can see that the elapsed time was displayed for each statement and for the script as a whole.

Finding out how many timers you have going

The TIMER command by itself will cause SQL*Plus to report the number of timers that are currently active. The following example shows how the count goes up each time you start a timer and back down each time you stop one:

SQL> TIMING START
SQL> TIMING
1 timing element in use
SQL> TIMING START
SQL> TIMING
2 timing elements in use
SQL> TIMING STOP
 real: 3510
SQL> TIMING
1 timing element in use
SQL> TIMING STOP
 real: 9170
SQL> TIMING
no timing elements in use

Stopping all timers

You can stop and delete all timers at once with the CLEAR TIMING command. As each timer is stopped, its final value is displayed. Here’s an example:

SQL> TIMING START first
SQL> TIMING START second
SQL> TIMING START third
SQL> CLEAR TIMING
timing for: third
 real: 2300
timing for: second
 real: 7250
timing for: first
 real: 10160
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.229.113