112

My application, which uses an Oracle database, is going slow or appears to have stopped completely.

How can find out which queries are most expensive, so I can investigate further?

10 Answers 10

155

This one shows SQL that is currently "ACTIVE":-

select S.USERNAME, s.sid, s.osuser, t.sql_id, sql_text
from v$sqltext_with_newlines t,V$SESSION s
where t.address =s.sql_address
and t.hash_value = s.sql_hash_value
and s.status = 'ACTIVE'
and s.username <> 'SYSTEM'
order by s.sid,t.piece
/

This shows locks. Sometimes things are going slow, but it's because it is blocked waiting for a lock:

select
  object_name, 
  object_type, 
  session_id, 
  type,         -- Type or system/user lock
  lmode,        -- lock mode in which session holds lock
  request, 
  block, 
  ctime         -- Time since current mode was granted
from
  v$locked_object, all_objects, v$lock
where
  v$locked_object.object_id = all_objects.object_id AND
  v$lock.id1 = all_objects.object_id AND
  v$lock.sid = v$locked_object.session_id
order by
  session_id, ctime desc, object_name
/

This is a good one for finding long operations (e.g. full table scans). If it is because of lots of short operations, nothing will show up.

COLUMN percent FORMAT 999.99 

SELECT sid, to_char(start_time,'hh24:mi:ss') stime, 
message,( sofar/totalwork)* 100 percent 
FROM v$session_longops
WHERE sofar/totalwork < 1
/
Sign up to request clarification or add additional context in comments.

2 Comments

Is there a way to safely kill such queries if they run for more than x minutes. Thanks for the answer though @UmberFerrule
@TommyT You can use alter system kill session as described here: docs.oracle.com/cd/B28359_01/server.111/b28310/…
41

Try this, it will give you queries currently running for more than 60 seconds. Note that it prints multiple lines per running query if the SQL has multiple lines. Look at the sid,serial# to see what belongs together.

select s.username,s.sid,s.serial#,s.last_call_et/60 mins_running,q.sql_text from v$session s 
join v$sqltext_with_newlines q
on s.sql_address = q.address
 where status='ACTIVE'
and type <>'BACKGROUND'
and last_call_et> 60
order by sid,serial#,q.piece

4 Comments

i run this query and it tell me is invalid statement
It;s valid. I tested it. What tool are you using to query? It might be getting confused with the # sign. Try changing the beginning and the end like this: "select * from ... order by sid,q.piece"
Also, you'll need to run this with a privledged account that has access to v$session, v$sqltext_with_newlines
This works but returns the SQL text of the query very strangely formatted.
10

v$session_longops

If you look for sofar != totalwork you'll see ones that haven't completed, but the entries aren't removed when the operation completes so you can see a lot of history there too.

1 Comment

Good hint. Also discussed in details here.
5
Step 1:Execute the query

column username format 'a10'
column osuser format 'a10'
column module format 'a16'
column program_name format 'a20'
column program format 'a20'
column machine format 'a20'
column action format 'a20'
column sid format '9999'
column serial# format '99999'
column spid format '99999'
set linesize 200
set pagesize 30
select
a.sid,a.serial#,a.username,a.osuser,c.start_time,
b.spid,a.status,a.machine,
a.action,a.module,a.program
from
v$session a, v$process b, v$transaction c,
v$sqlarea s
Where
a.paddr = b.addr
and a.saddr = c.ses_addr
and a.sql_address = s.address (+)
and to_date(c.start_time,'mm/dd/yy hh24:mi:ss') <= sysdate - (15/1440) -- running for 15 minutes
order by c.start_time
/   

Step 2: desc v$session

Step 3:select sid, serial#,SQL_ADDRESS, status,PREV_SQL_ADDR from v$session where sid='xxxx' //(enter the sid value)

Step 4: select sql_text from v$sqltext where address='XXXXXXXX';

Step 5: select piece, sql_text from v$sqltext where address='XXXXXX' order by piece;

Comments

2

You can check the long-running queries details like % completed and remaining time using the below query:

 SELECT SID, SERIAL#, OPNAME, CONTEXT, SOFAR, 
 TOTALWORK,ROUND(SOFAR/TOTALWORK*100,2) "%_COMPLETE" 
 FROM V$SESSION_LONGOPS 
 WHERE OPNAME NOT LIKE '%aggregate%' 
       AND TOTALWORK != 0 
       AND SOFAR <> TOTALWORK;

For the complete list of troubleshooting steps, you can check here:Troubleshooting long running sessions

Comments

2

You can use the v$sql_monitor view to find queries that are running longer than 5 seconds. This may only be available in Enterprise versions of Oracle. For example this query will identify slow running queries from my TEST_APP service:

select to_char(sql_exec_start, 'dd-Mon hh24:mi'), (elapsed_time / 1000000) run_time,
       cpu_time, sql_id, sql_text 
from   v$sql_monitor
where  service_name = 'TEST_APP'
order  by 1 desc;

Note elapsed_time is in microseconds so / 1000000 to get something more readable

1 Comment

For me this yielded "ORA-00942: table or view does not exist". Does one have to enable anything beforehand?
2
  1. Find active sessions:

enter image description here

  1. Find expensive SQL statements:

enter image description here

  1. Find SQL in active sessions:

enter image description here

  1. Find Long Running Transactions:

    col sid format 9999999 col serial# for 9999999 column opname format a14 column message format a41 set lines 1000 set pages 100 select sid,serial#,sql_id,opname,message,sofar,totalwork,round((sofar/decode(totalwork,0,1,totalwork))*100,2) work_done, time_remaining Time_remain,ELAPSED_SECONDS ela_seconds from v$session_longops where sofar<>totalwork ;

  2. Sql Monitoring:

    SELECT sql_id, status, elapsed_time, cpu_time, user_io_wait_time, sql_exec_id FROM v$sql_monitor ORDER BY elapsed_time DESC; enter image description here

  3. Generate AWR/ASM Report to find the most resource-intensive SQL

    @?/rdbms/admin/awrrpt.sql @?/rdbms/admin/ashrpt.sql

  4. Check for SQL Tuning advisory report to get 15 most resource-intensive SQL along with the recommendation to fix.

Hope the above steps will help you in fixing your issue !! :)

Comments

1

You can generate an AWR (automatic workload repository) report from the database.

Run from the SQL*Plus command line:

SQL> @$ORACLE_HOME/rdbms/admin/awrrpt.sql

Read the document related to how to generate & understand an AWR report. It will give a complete view of database performance and resource issues. Once we are familiar with the AWR report it will be helpful to find Top SQL which is consuming resources.

Also, in the 12C EM Express UI we can generate an AWR.

Comments

0
select sq.PARSING_SCHEMA_NAME, sq.LAST_LOAD_TIME, sq.ELAPSED_TIME, sq.ROWS_PROCESSED, ltrim(sq.sql_text), sq.SQL_FULLTEXT
  from v$sql sq, v$session se
 order by sq.ELAPSED_TIME desc, sq.LAST_LOAD_TIME desc;

Comments

0

This one returns the most expensive queries, and the SQL which caused them:

SELECT vsl.opname, vsl.target, vsl.totalwork, vsl.units, vsl.elapsed_seconds, vsl.message, vs.sql_text FROM v$session_longops vsl
  JOIN v$sql vs ON vsl.sql_id = vs.sql_id
ORDER BY vsl.elapsed_seconds DESC

So in a multi-service environment it might help to identify the service and function causing slowness.

Comments