Oracle Scratchpad

April 10, 2007

SQL Costs

Filed under: Performance,Troubleshooting — Jonathan Lewis @ 8:31 pm GMT Apr 10,2007

Here’s a quick and dirty bit of SQL I use from time to time to check whats going on with a “popular” piece of SQL, i.e. a piece of code that is run very frequently. All it does is compare a few of the statistics from v$sql with their previous values from the last time the script was run. 

As you can see, the script is the 10g version, using the sql_id to access a single statement in the library cache with maximum efficiency – change this to the hash_value for earlier versions of Oracle.

All I do with this script is identify a single ‘interesting’ statement – possibly by checking a recent statspack report for the the most frequently executed statements – and slot in the appropriate sql_id and child_number. Of course, some statements will have multiple child cursors, so a precursor to setting up this script is to pick an interesting child.

As you can see, I use the SQL*Plus new_value feature to capture the most recent values reported for the statistics I am interested in – but use the previous captured values to generate the ‘deltas’. (And to get things going, I define the inputs as zero for the first run of the script).

So all you do is pick your statement, adjust the script, then run it every few seconds for a couple of minutes.

Occasionally it’s nice to have something like this to sample v$sql in near-real time rather than relying on the longer-term averages you get from statspack as an indicator of the work done and results acquired by a single statement. You’ll have to adjust the SQL_ID and CHILD_NUMBER as required, of course; and you could always query v$sqlstats in 10g, or v$sqlstats_plan_hash in 11g.


set linesize 144
set verify off

column	executions	new_value m_exe_ct
column	rows_processed	new_value m_row_ct
column	buffer_gets	new_value m_buf_ct
column	disk_reads	new_value m_dsk_ct

define m_exe_ct = 0
define m_row_ct = 0
define m_buf_ct = 0
define m_dsk_ct = 0

select
	sql_id,
	child_number,
	executions,
	executions - &m_exe_ct 			exe_delta,
	buffer_gets,
	buffer_gets - &m_buf_ct 		buf_delta,
	disk_reads,
	disk_reads - &m_dsk_ct 			dsk_delta,
	rows_processed,
	rows_processed - &m_row_ct 		row_delta,
	round(
		(rows_processed - &m_row_ct) /
		nullif(executions - &m_exe_ct,0)
	)					rows_per_exe,
	round(
		(buffer_gets - &m_buf_ct) /
		nullif(executions - &m_exe_ct,0)
	)					bufs_per_exe,
	round(
		(disk_reads - &m_dsk_ct) /
		nullif(executions - &m_exe_ct,0)
	)					dsks_per_exe
from
	v$sql
where
	sql_id = '6vba5y39vcq1f'
and	child_number = 0
;

Obviously, you can follow the pattern of the code to pick your own metrics – I tend to find “work done per row” and “work done per execution” quite helpful; you may want to review work done in terms of CPU time, sorts, and any other basic metrics available in the view – unfortunately you have to be a little selective otherwise the output gets a bit too wide for comfort.

I’ve attached a sample of the output from running the above query a few times – but I’ve manually adjusted the output, eliminating columns, to allow it to fit on the page; I’ve also deleted the row returned on the first run where the deltas and the base figures are the same:

SQL> /

EXECUTIONS EXE_DELTA  BUFFER_GETS  BUF_DELTA ROWS_PROCESSED ROW_DELTA  ROWS_PER_EXE BUFS_PER_EXE
---------- ---------- ----------- ---------- -------------- ---------- ------------ ------------
   1663712         19   892482440       7355      114727466        469           25          387

SQL> /

EXECUTIONS EXE_DELTA  BUFFER_GETS  BUF_DELTA ROWS_PROCESSED  ROW_DELTA ROWS_PER_EXE BUFS_PER_EXE
---------- ---------- ----------- ---------- -------------- ---------- ------------ ------------
   1663728         16   892488545       6105      114727910        444           28          382

SQL> /

EXECUTIONS EXE_DELTA  BUFFER_GETS  BUF_DELTA ROWS_PROCESSED  ROW_DELTA ROWS_PER_EXE BUFS_PER_EXE
---------- ---------- ----------- ---------- -------------- ---------- ------------ ------------
   1663744         16   892496194       7649      114728240        330           21          478

In this case, the sampling showed that the costs and result sets were fairly stable – the interesting cases tend to be the ones which show a very wide variation in costs or results.

2 Comments »

  1. You might also expand it to check whether something has changed recently – comparing resource/executions against your resource_delta/executions_delta.

    Comment by Alberto Dell'Era — April 11, 2007 @ 9:48 pm GMT Apr 11,2007 | Reply

  2. […] What have I done: a script to report the work done, time spent, and wait events for my session Tracking one statement: and article describing a way of watching the work done by a critical statement as time […]

    Pingback by Simple scripts « Oracle Scratchpad — February 28, 2010 @ 5:35 pm GMT Feb 28,2010 | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Rubric Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 4,521 other followers