Press ESC to close

SQL FOR ORACLE DBA -2 : Performance & Top SQL Analysis

This blog post focuses on Oracle performance troubleshooting and Top SQL analysis techniques for DBAs. It includes practical SQL scripts to identify high resource-consuming SQL statements, analyze wait events, monitor memory and execution time usage, detect execution plan changes, and investigate AWR snapshot-based performance issues in Oracle databases.

TOP 10 SQL EVENT

SELECT * FROM (
  SELECT
    h.event "Wait Event",
    SUM(h.wait_time + h.time_waited)/1000000 "Total Wait Time"
    FROM gv$active_session_history h,
         gv$event_name e
   WHERE h.sample_time < (SELECT MAX(sample_time)
                            FROM gv$active_session_history)
     AND h.sample_time > (SELECT MAX(sample_time) - 1/24
                            FROM gv$active_session_history)
     AND h.event_id = e.event_id
     AND e.wait_class <>'IDLE'
   GROUP BY h.event
   ORDER BY 2 DESC)
  WHERE ROWNUM <10;

SESSION COUNT, SQL, EVENT, VS….

-- Instance 

select INST_ID,count(*) toplam from gv$session  where status='ACTIVE' and type != 'BACKGROUND' group by INST_ID;

--Module

select module,INST_ID,count(*) toplam from gv$session  where status='ACTIVE' and  type != 'BACKGROUND' group by module,INST_ID order by toplam desc;

--Machine

select inst_id,machine,count(*) toplam from gv$session where machine is not null group by machine,inst_id order by toplam desc

--Running SQL count on Instance

select inst_id,count(*) from gv$sql group by inst_id;

The SQL queries and SQL IDs that consume the most CPU are:

SELECT ss.SID, se.serial#, ss.VALUE, se.osuser, se.username, se.sql_id,  se.prev_Sql_id, logon_time, status FROM v$sesstat ss, v$session se
 WHERE 
 VALUE > 0 
   AND ss.SID = se.SID
   AND status = 'ACTIVE'  ORDER BY VALUE DESC

--veya 

select * from ( SELECT parsing_schema_name "Owner",
         last_load_time,
         last_active_time,
         executions,
         rows_processed,
         sql_id,
         ROUND (rows_processed / executions) AS "RowCount",
         ROUND (cpu_time / executions) AS "CpuTimeCount",
         ROUND (buffer_gets / executions) AS "MemoryCount",
         ROUND (disk_reads / executions) AS "DiskReadCount",
         executions "# of Executions",
         (elapsed_time / executions) / 1000000 AS "TimeSpend sec.",
         DBMS_LOB.SUBSTR (SQL_FULLTEXT, 4000, 1) AS SqlFullText
    FROM gv$sql
   WHERE executions > 0
    -- AND parsing_schema_name = :schema_name
     AND TRUNC (last_active_time) = TRUNC (SYSDATE)
ORDER BY 8 DESC)
where rownum <21       ;

Longops query

SET VERIFY OFF PAGESIZE 100 LINESIZE 500
COL SID FORMAT 99999
COL SERIAL# FORMAT 99999
COL OPNAME FORMAT A35
COL USERNAME FORMAT A12
COL OSUSER FORMAT A15
COL TOTALWORK FORMAT 999999999
COL SOFAR FORMAT 999999999
COL PERCENT_COMPLETE HEADING "YUZDE" FORMAT A12
COL START_TIME FORMAT A10
COL "TIME (MINS)" FORMAT 999999
COL "ETF (MINS)" FORMAT 999999
SELECT A.SID, A.SERIAL#, A.OPNAME, B.USERNAME, B.OSUSER
     ,A.TOTALWORK ,A.SOFAR ,ROUND((A.SOFAR/A.TOTALWORK)*100,2)||'%' AS PERCENT_COMPLETE
     ,TO_CHAR(A.START_TIME ,'HH24:MI:SS') AS START_TIME
     ,ROUND((SYSDATE - A.START_TIME)*1440,0) AS "TIME (MINS)"
     ,ROUND(DECODE((ROUND((A.SOFAR/A.TOTALWORK)*100,2)),  0, NULL, (ROUND((SYSDATE - A.START_TIME)*1440,1)) * 100 / (ROUND((A.SOFAR/A.TOTALWORK)*100,2))),0) AS "ETF (MINS)"
  FROM GV$SESSION_LONGOPS A, GV$SESSION B
 WHERE A.SID=B.SID
   AND A.SERIAL#=B.SERIAL#
   AND A.SOFAR <> A.TOTALWORK AND A.TOTALWORK <> 0
 ORDER BY A.TOTALWORK DESC;

— Finding SNAP_ID values for a given date range

SELECT MIN (snap_id) || ' and ' || MAX (snap_id)
FROM dba_hist_snapshot
WHERE begin_interval_time <=
TO_DATE ('2019/08/26 12:00:00', 'YYYY/MM/DD HH24:MI:SS')
AND begin_interval_time >=
TO_DATE ('2019/08/26 08:00:00', 'YYYY/MM/DD HH24:MI:SS')

SQL script that provides Time, Memory and Wait Event details  for SQL statements within a specific date range / snap interval

select event,wait_class,sql_id,
starting_time,
end_time,
(EXTRACT(HOUR FROM run_time) * 3600
+ EXTRACT(MINUTE FROM run_time) * 60
+ EXTRACT(SECOND FROM run_time)) run_time_sec,
READ_IO_BYTES,
PGA_ALLOCATED PGA_ALLOCATED_BYTES,
TEMP_ALLOCATED TEMP_ALLOCATED_BYTES
from (
select event,wait_class,
sql_id,
max(sample_time - sql_exec_start) run_time,
max(sample_time) end_time,
sql_exec_start starting_time,
sum(DELTA_READ_IO_BYTES) READ_IO_BYTES,
sum(DELTA_PGA) PGA_ALLOCATED,
sum(DELTA_TEMP) TEMP_ALLOCATED
from
(
select event,wait_class,sql_id,
sample_time,
sql_exec_start,
DELTA_READ_IO_BYTES,
sql_exec_id,
greatest(PGA_ALLOCATED - first_value(PGA_ALLOCATED) over (partition by sql_id,sql_exec_id order by sample_time rows 1 preceding),0) DELTA_PGA,
greatest(TEMP_SPACE_ALLOCATED - first_value(TEMP_SPACE_ALLOCATED) over (partition by sql_id,sql_exec_id order by sample_time rows 1 preceding),0) DELTA_TEMP
from
dba_hist_active_sess_history
where snap_id between 220563 and 220565
-- sample_time >= to_date ('2019/08/20 08:00:00','YYYY/MM/DD HH24:MI:SS')
-- and sample_time < to_date ('2019/08/20 11:00:00','YYYY/MM/DD HH24:MI:SS')
and sql_exec_start is not null
and IS_SQLID_CURRENT='Y'
)
group by event,wait_class,sql_id,SQL_EXEC_ID,sql_exec_start
order by sql_id
)
where sql_id = 'b0wkusa4hj4fn'
order by sql_id, run_time_sec desc;

ACTIVE SESSION HISTORY AND SQL 

-- SESSIN WAIT COUNTS
SELECT EVENT,COUNT(*) FROM V$SESSION WHERE STATUS='ACTIVE' AND TYPE <> 'BACKGROUND' GROUP BY EVENT ORDER BY 2 DESC;

-- ACTIVE SESSIONS SQL
SET LINESIZE 1000
SET PAGESIZE 1000
COL I_ID FOR 99
COL USERNAME FOR A10
COL OSUSER FOR A8
COL MACHINE FOR A15
COL DBSID FOR 9999
COL DBPID FOR A7
COL APPPID FOR A7
COL STATUS FOR A7
COL EX_TIME_MINs FOR 9999
COL BLCKNG_SE FOR A10
COL SQL_ID FOR A13
COL REMIN_SEC FOR 9999
COL MODULE FOR A10
COL PROGRAM FOR A10
COL WAIT_CLASS FOR A12
COL EVENT FOR A25
COL W_TIME FOR 9999
COL KILL FOR A25
COL OS_KILL FOR A10
COL SQL_FULLTEXT FOR A31
SELECT A.*, SQ.SQL_FULLTEXT FROM
( SELECT S.INST_ID I_ID, SUBSTR(S.USERNAME,1,10) "USERNAME", SUBSTR(S.OSUSER,1,10) "OSUSER", SUBSTR(S.MACHINE,1,15) "MACHINE", S.SID DBSID, P.SPID DBPID, S.PROCESS APPPID, S.STATUS, ROUND(S.LAST_CALL_ET/60, 2) "EX_TIME_MINs"
        ,CASE WHEN S.BLOCKING_SESSION IS NULL THEN NULL ELSE S.BLOCKING_SESSION || ' @ ' || S.BLOCKING_INSTANCE END AS "BLCKNG_SE"
        , S.SQL_ID, ROUND(W.TIME_REMAINING_MICRO/1000000) "REMIN_SEC", SUBSTR(S.MODULE,1,10) "MODULE", S.PROGRAM
        , S.WAIT_CLASS, W.EVENT, ROUND(W.WAIT_TIME_MICRO/1000000) "W_TIME"
        ,'ALTER SYSTEM KILL SESSION '''|| S.SID || ',' || S.SERIAL#|| ',@' || S.INST_ID || ''' IMMEDIATE;' AS KILL
        ,'kill -9 ' || P.SPID AS OS_KILL
    FROM GV$SESSION S 
        INNER JOIN GV$PROCESS P ON S.PADDR = P.ADDR 
        INNER JOIN GV$SESSION_WAIT W ON S.SID=W.SID AND S.INST_ID=W.INST_ID
    WHERE 1=1
	--AND S.USERNAME NOT IN ('SYS','SYSTEM') AND S.USERNAME IS NOT NULL
   --AND S.SID in (112)
   --AND P.SPID = 6672
   --AND S.SQL_ID='18PBS6PW1FDH2'
   --AND S.BLOCKING_SESSION IS NOT NULL
   --AND s.PROGRAM like '%rman%'
   AND S.TYPE <> 'BACKGROUND' 
   AND S.STATUS = 'ACTIVE'
) A LEFT JOIN GV$SQL SQ ON A.SQL_ID = SQ.SQL_ID AND A.I_ID = SQ.INST_ID
WHERE SQ.USERS_EXECUTING=1
ORDER BY 9 DESC;

HISTORICAL ACTIVE SESSIONS SQL

SELECT a.instance_number, a.sample_time, a.blocking_session, a.session_id, a.event, a.session_state, a.SQL_PLAN_OPERATION, a.sql_id, a.machine, b.sql_text  
  FROM dba_hist_active_sess_history a, gv$sql b
WHERE a.sql_id = b.sql_id
--and a.sample_time BETWEEN to_date('09.10.2018 02:00','dd.mm.yyyy hh24:mi:ss') AND to_date('09.10.2018 09:45','dd.mm.yyyy hh24:mi:ss')
and a.sample_time BETWEEN ('09/07/20199 08:50:00:000') and ('09/07/20199 10:40:00:000')
--and a.session_id = 4843
--and b.sql_text not like 'SELECT%'
order by a.sample_time

LOAD AVERAGE for ACTIVE SESSIONS

SELECT ROUND ((COUNT (ash.sample_id) / ((CAST (end_time.sample_time AS DATE) - CAST (start_time.sample_time AS DATE)) * 24 * 60 * 60)), 2) AS Average_Active_Session
FROM (SELECT MIN (sample_time) sample_time FROM gv$active_session_history ash  WHERE sample_time BETWEEN SYSDATE - 1 / 1440 AND SYSDATE) start_time,
     (SELECT MAX (sample_time) sample_time FROM gv$active_session_history WHERE sample_time BETWEEN SYSDATE - 1 / 1440 AND SYSDATE) end_time,
     gv$active_session_history ash
WHERE ash.sample_time BETWEEN start_time.sample_time AND end_time.sample_time
GROUP BY end_time.sample_time, start_time.sample_time;

Sql Tuning Advisor Kullanımı sql id için

DECLARE
  l_sql_tune_task_id  VARCHAR2(100);
BEGIN
  l_sql_tune_task_id := DBMS_SQLTUNE.create_tuning_task (
                          sql_id      => '87s8z2zzpsg88',
                          scope       => DBMS_SQLTUNE.scope_comprehensive,
                          time_limit  => 500,
                          task_name   => '87s8z2zzpsg88_tuning_task11',
                          description => 'Tuning task1 for statement 87s8z2zzpsg88');
  DBMS_OUTPUT.put_line('l_sql_tune_task_id: ' || l_sql_tune_task_id);
END;
/


EXEC DBMS_SQLTUNE.execute_tuning_task(task_name => '87s8z2zzpsg88_tuning_task11'); 


select dbms_sqltune.report_tuning_task('87s8z2zzpsg88_tuning_task11') from dual;

QL script to check whether a SQL execution plan has changed

select distinct sql_plan_hash_value from dba_hist_active_sess_history where sql_id='a77kxmcjfty2w';

select distinct(plan_hash_value) from dba_hist_sql_plan where sql_id='a77kxmcjfty2w';

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir