Files
oracle-jump-query-public/references/sys-functions/henlo_ora_monitor.sql
T

135 lines
10 KiB
SQL

-- HENLO_ORA_MONITOR v3.0
-- DBA only. Replace <AGENT_SCHEMA> before execution.
-- Returns JSON in a CLOB. This return contract is required by Agent 1.8.6+.
CREATE OR REPLACE FUNCTION SYS.HENLO_ORA_MONITOR(
P_ITEM VARCHAR2, P_MINUTES NUMBER DEFAULT 60, P_TOP_N NUMBER DEFAULT 20
) RETURN CLOB AUTHID DEFINER IS
L_ITEM VARCHAR2(64) := LOWER(TRIM(P_ITEM));
L_SQL VARCHAR2(32767);
L_TITLE VARCHAR2(200);
L_RESULT CLOB;
L_ROWS CLOB;
L_COLS CLOB;
L_CUR INTEGER;
L_COL_COUNT INTEGER;
L_DESC DBMS_SQL.DESC_TAB2;
L_VALUE VARCHAR2(4000);
L_ROW_COUNT NUMBER := 0;
L_TOP_N NUMBER := LEAST(GREATEST(NVL(P_TOP_N, 20), 1), 100);
L_EXEC INTEGER;
FUNCTION ESC(P_TEXT VARCHAR2) RETURN VARCHAR2 IS
BEGIN
IF P_TEXT IS NULL THEN RETURN ''; END IF;
RETURN REPLACE(REPLACE(REPLACE(REPLACE(P_TEXT, '\', '\\'), '"', '\"'), CHR(13), ' '), CHR(10), ' ');
END;
PROCEDURE APPEND_TEXT(P_TEXT VARCHAR2) IS
BEGIN
DBMS_LOB.WRITEAPPEND(L_RESULT, LENGTH(P_TEXT), P_TEXT);
END;
BEGIN
IF L_ITEM = 'capabilities' THEN
L_TITLE := 'Monitor capabilities';
L_SQL := 'SELECT ''3.0'' function_version, ''active_slow_sql,history_top_sql,fullscan_sql,plan_heavy_sql,blocking_locks,long_transactions,inactive_sessions,session_counts,cache_hit,datafiles,undo,memory,io_waits,background_process,ora_errors,invalid_objects,tablespace,instance_status,awr_snapshots'' supported_items FROM dual';
ELSIF L_ITEM = 'instance_status' THEN
L_TITLE := 'Instance status';
L_SQL := 'SELECT i.status, d.open_mode, d.log_mode, TO_CHAR(i.startup_time,''YYYY-MM-DD HH24:MI:SS'') startup_time, i.instance_name FROM v$instance i CROSS JOIN v$database d';
ELSIF L_ITEM = 'active_slow_sql' THEN
L_TITLE := 'Active slow SQL';
L_SQL := 'SELECT * FROM (SELECT s.sid, s.serial# serial_no, s.username, s.machine, s.program, q.sql_id, SUBSTR(q.sql_text,1,500) sql_text, s.last_call_et elapsed_sec, s.status, s.event, s.wait_class FROM v$session s LEFT JOIN v$sql q ON s.sql_id=q.sql_id WHERE s.status=''ACTIVE'' AND s.type<>''BACKGROUND'' ORDER BY s.last_call_et DESC) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'history_top_sql' THEN
L_TITLE := 'AWR top SQL';
L_SQL := 'SELECT * FROM (SELECT s.sql_id, ROUND(SUM(s.elapsed_time_delta)/1000000,2) total_elapsed_s, ROUND(SUM(s.cpu_time_delta)/1000000,2) total_cpu_s, SUM(s.executions_delta) executions, SUBSTR(MAX(t.sql_text),1,500) sql_text FROM dba_hist_sqlstat s JOIN dba_hist_snapshot sn ON s.snap_id=sn.snap_id AND s.dbid=sn.dbid AND s.instance_number=sn.instance_number JOIN dba_hist_sqltext t ON s.sql_id=t.sql_id AND s.dbid=t.dbid WHERE sn.begin_interval_time>=SYSDATE-(NVL(' || NVL(P_MINUTES,60) || ',60)/1440) GROUP BY s.sql_id ORDER BY total_elapsed_s DESC) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'fullscan_sql' THEN
L_TITLE := 'Possible full scan SQL';
L_SQL := 'SELECT * FROM (SELECT sql_id, executions, rows_processed, SUBSTR(sql_text,1,500) sql_text FROM v$sql WHERE executions>100 AND LOWER(sql_text) LIKE ''%select%from%'' AND LOWER(sql_text) NOT LIKE ''%where%'' ORDER BY rows_processed DESC) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'plan_heavy_sql' THEN
L_TITLE := 'High buffer SQL';
L_SQL := 'SELECT * FROM (SELECT sql_id, plan_hash_value, buffer_gets, disk_reads, executions, ROUND(buffer_gets/DECODE(executions,0,1,executions),2) avg_buffer_gets FROM v$sql WHERE executions>0 ORDER BY buffer_gets DESC) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'blocking_locks' THEN
L_TITLE := 'Blocking locks';
L_SQL := 'SELECT * FROM (SELECT l.sid blocker_sid, s1.serial# blocker_serial, s1.username blocker_user, w.sid waiter_sid, s2.serial# waiter_serial, s2.username waiter_user, l.lmode locked_mode, s2.event wait_event FROM v$lock l LEFT JOIN v$session s1 ON l.sid=s1.sid LEFT JOIN v$lock w ON l.id1=w.id1 AND l.id2=w.id2 AND w.request>0 LEFT JOIN v$session s2 ON w.sid=s2.sid WHERE l.block=1) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'long_transactions' THEN
L_TITLE := 'Long transactions';
L_SQL := 'SELECT * FROM (SELECT s.sid, s.serial# serial_no, s.username, t.start_time, t.used_ublk, t.used_urec, s.sql_id FROM v$transaction t JOIN v$session s ON t.ses_addr=s.saddr ORDER BY t.start_time) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'inactive_sessions' THEN
L_TITLE := 'Inactive sessions';
L_SQL := 'SELECT * FROM (SELECT sid, serial# serial_no, username, machine, program, last_call_et FROM v$session WHERE status=''INACTIVE'' AND last_call_et>1800 ORDER BY last_call_et DESC) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'session_counts' THEN
L_TITLE := 'Session counts';
L_SQL := 'SELECT SUM(CASE WHEN status=''ACTIVE'' AND type<>''BACKGROUND'' THEN 1 ELSE 0 END) active_sessions, SUM(CASE WHEN type<>''BACKGROUND'' THEN 1 ELSE 0 END) total_sessions FROM v$session';
ELSIF L_ITEM = 'cache_hit' THEN
L_TITLE := 'Cache hit ratio';
L_SQL := 'SELECT ''BUFFER_CACHE'' metric, ROUND((1-pr.value/NULLIF(cg.value+bg.value,0))*100,2) hit_percent FROM v$sysstat pr,v$sysstat cg,v$sysstat bg WHERE pr.name=''physical reads'' AND cg.name=''consistent gets'' AND bg.name=''db block gets'' UNION ALL SELECT ''LIBRARY_CACHE'',ROUND(SUM(pinhits)/NULLIF(SUM(pins),0)*100,2) FROM v$librarycache';
ELSIF L_ITEM = 'datafiles' THEN
L_TITLE := 'Datafiles';
L_SQL := 'SELECT * FROM (SELECT file_name,tablespace_name,ROUND(bytes/1024/1024/1024,2) curr_gb,ROUND(maxbytes/1024/1024/1024,2) max_gb,ROUND(bytes/DECODE(maxbytes,0,bytes,maxbytes)*100,2) file_used_pct FROM dba_data_files WHERE maxbytes>0 ORDER BY file_used_pct DESC) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'undo' THEN
L_TITLE := 'Undo usage';
L_SQL := 'SELECT * FROM (SELECT tablespace_name,status,ROUND(SUM(bytes)/1024/1024/1024,2) gb FROM dba_undo_extents GROUP BY tablespace_name,status ORDER BY gb DESC) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'memory' THEN
L_TITLE := 'SGA and PGA';
L_SQL := 'SELECT metric,value_mb FROM (SELECT ''PGA_USED'' metric,ROUND(SUM(pga_used_mem)/1024/1024,2) value_mb FROM v$process UNION ALL SELECT ''PGA_ALLOC'',ROUND(SUM(pga_alloc_mem)/1024/1024,2) FROM v$process UNION ALL SELECT component,ROUND(current_size/1024/1024,2) FROM v$sga_dynamic_components) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'io_waits' THEN
L_TITLE := 'IO waits';
L_SQL := 'SELECT * FROM (SELECT event,wait_class,total_waits,ROUND(time_waited/100,2) time_waited_sec,ROUND(average_wait/100,2) avg_wait_ms FROM v$system_event WHERE wait_class IN (''User I/O'',''System I/O'') ORDER BY time_waited_sec DESC) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'background_process' THEN
L_TITLE := 'Background processes';
L_SQL := 'SELECT * FROM (SELECT pname,status,program,spid FROM v$process WHERE background=1 ORDER BY pname) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'ora_errors' THEN
L_TITLE := 'Recent ORA errors';
L_SQL := 'SELECT * FROM (SELECT originating_timestamp origin_timestamp,SUBSTR(message_text,1,1000) message_text FROM v$diag_alert_ext WHERE originating_timestamp>=SYSTIMESTAMP-NUMTODSINTERVAL(NVL(' || NVL(P_MINUTES,60) || ',60),''MINUTE'') AND message_text LIKE ''%ORA-%'' ORDER BY originating_timestamp DESC) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'invalid_objects' THEN
L_TITLE := 'Invalid objects';
L_SQL := 'SELECT * FROM (SELECT object_type,owner,object_name,status FROM dba_objects WHERE status<>''VALID'' ORDER BY owner,object_type,object_name) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'tablespace' THEN
L_TITLE := 'Tablespace usage';
L_SQL := 'SELECT * FROM (SELECT df.tablespace_name,ROUND(df.total_bytes/1024/1024/1024,2) total_gb,ROUND((df.total_bytes-NVL(fs.free_bytes,0))/1024/1024/1024,2) used_gb,ROUND(NVL(fs.free_bytes,0)/1024/1024/1024,2) free_gb,ROUND((df.total_bytes-NVL(fs.free_bytes,0))/df.total_bytes*100,2) used_pct FROM (SELECT tablespace_name,SUM(bytes) total_bytes FROM dba_data_files GROUP BY tablespace_name) df LEFT JOIN (SELECT tablespace_name,SUM(bytes) free_bytes FROM dba_free_space GROUP BY tablespace_name) fs ON df.tablespace_name=fs.tablespace_name ORDER BY used_pct DESC) WHERE ROWNUM<=' || L_TOP_N;
ELSIF L_ITEM = 'awr_snapshots' THEN
L_TITLE := 'AWR snapshots';
L_SQL := 'SELECT * FROM (SELECT snap_id,dbid,instance_number,begin_interval_time,end_interval_time FROM dba_hist_snapshot ORDER BY snap_id DESC) WHERE ROWNUM<=' || L_TOP_N;
ELSE
RETURN '{"success":false,"item":"' || ESC(L_ITEM) || '","title":"Unknown","status":"failed","columns":[],"rows":[],"warnings":[],"error":"unknown item"}';
END IF;
DBMS_LOB.CREATETEMPORARY(L_RESULT, TRUE);
DBMS_LOB.CREATETEMPORARY(L_ROWS, TRUE);
DBMS_LOB.CREATETEMPORARY(L_COLS, TRUE);
L_CUR := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(L_CUR, L_SQL, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS2(L_CUR, L_COL_COUNT, L_DESC);
FOR I IN 1..L_COL_COUNT LOOP
DBMS_SQL.DEFINE_COLUMN(L_CUR, I, L_VALUE, 4000);
IF I > 1 THEN DBMS_LOB.WRITEAPPEND(L_COLS, 1, ','); END IF;
DBMS_LOB.WRITEAPPEND(L_COLS, LENGTH(L_DESC(I).COL_NAME) + 2, '"' || ESC(L_DESC(I).COL_NAME) || '"');
END LOOP;
L_EXEC := DBMS_SQL.EXECUTE(L_CUR);
WHILE DBMS_SQL.FETCH_ROWS(L_CUR) > 0 LOOP
L_ROW_COUNT := L_ROW_COUNT + 1;
IF L_ROW_COUNT > 1 THEN DBMS_LOB.WRITEAPPEND(L_ROWS, 1, ','); END IF;
DBMS_LOB.WRITEAPPEND(L_ROWS, 1, '[');
FOR I IN 1..L_COL_COUNT LOOP
DBMS_SQL.COLUMN_VALUE(L_CUR, I, L_VALUE);
IF I > 1 THEN DBMS_LOB.WRITEAPPEND(L_ROWS, 1, ','); END IF;
L_VALUE := '"' || ESC(SUBSTR(L_VALUE, 1, 1000)) || '"';
DBMS_LOB.WRITEAPPEND(L_ROWS, LENGTH(L_VALUE), L_VALUE);
END LOOP;
DBMS_LOB.WRITEAPPEND(L_ROWS, 1, ']');
END LOOP;
DBMS_SQL.CLOSE_CURSOR(L_CUR);
APPEND_TEXT('{"success":true,"item":"' || ESC(L_ITEM) || '","title":"' || ESC(L_TITLE) || '","status":"normal","columns":[');
DBMS_LOB.APPEND(L_RESULT, L_COLS);
APPEND_TEXT('],"rows":[');
DBMS_LOB.APPEND(L_RESULT, L_ROWS);
APPEND_TEXT('],"warnings":[]}');
RETURN L_RESULT;
EXCEPTION
WHEN OTHERS THEN
IF DBMS_SQL.IS_OPEN(L_CUR) THEN DBMS_SQL.CLOSE_CURSOR(L_CUR); END IF;
RETURN '{"success":false,"item":"' || ESC(L_ITEM) || '","title":"' || ESC(NVL(L_TITLE,L_ITEM)) || '","status":"failed","columns":[],"rows":[],"warnings":[],"error":"' || ESC(SQLERRM) || '"}';
END;
/
GRANT EXECUTE ON SYS.HENLO_ORA_MONITOR TO <AGENT_SCHEMA>;