1. 程式人生 > 資料庫 >TOP SQL監控之oracle篇

TOP SQL監控之oracle篇

資料庫SQL的監控和優化的核心,其實主要在於“行讀”!
監控找出行讀高的SQL,而優化的最直接手段就是降低行讀數。

oracle的監控方法和監控工具可能有千百種,這裡介紹我常用的幾種簡單而直接的方式:

注意:以下監控SQL需要使用者有oracle的管理檢視查詢許可權。

1、根據pid查SQL

TOP SQL監控之oracle篇

假如你的oracle此時響應速度較慢,從伺服器的TOP可以看到oracle程序佔用了較多CPU,或者有較多的iowait,那麼可以直接用下面的SQL語句來查詢正在執行的較耗資源的SQL。

SELECT A.,B.SQLTEXT FROM
    (SELECT z.SPID AS 作業系統PID
,x.SID
, x.SERIAL#
, x.USERNAME
, x.SQLID
    FROM v$session x
, v$process z
    WHERE x.PADDR = z.ADDR  
    AND Z.SPID = '10341')A
    LEFT JOIN v$sql B ON A.SQLID = B.SQLID;

恭喜你,你可能已經直接找到有問題的SQL了。
TOP SQL監控之oracle篇

2、正在執行中的SQL

如果不知道pid,那稍微改動下上面的SQL,可以直接查當前oracle庫正在執行的所有SQL,按照時間倒序排序,一樣能抓到最可疑的SQL。

SELECT z.SPID AS 作業系統PID
,x.SID
, x.SERIAL#
, x.USERNAME
, x.LOCKWAIT
, x.STATUS
, x.SCHEMANAME
, x.OSUSER
, x.PROCESS
, x.MACHINE
, x.PORT
, x.PROGRAM
, x.SQL_ID
, x.SQL_CHILD_NUMBER
, x.SQL_EXEC_START
, x.PREV_SQL_ID
, CASE x.ROW_WAIT_OBJ# WHEN - 1 THEN NULL ELSE (dbms_rowid.rowid_create (1, ROW_WAIT_OBJ#, ROW_WAIT_FILE#, ROW_WAIT_BLOCK#, ROW_WAIT_ROW#)) END AS rowinfo
, x.LAST_CALL_ET
, x.BLOCKING_SESSION_STATUS
, x.BLOCKING_SESSION
, x.FINAL_BLOCKING_SESSION_STATUS
, x.FINAL_BLOCKING_SESSION
, x.EVENT
, x.WAIT_CLASS
, x.STATE
, x.WAIT_TIME_MICRO
, y.SQL_TEXT
, y.EXECUTIONS
, CASE EXECUTIONS WHEN 0 THEN y.BUFFER_GETS ELSE y.BUFFER_GETS / EXECUTIONS END AS AVG_BUFFER_GETS
, CASE EXECUTIONS WHEN 0 THEN y.DISK_READS ELSE y.DISK_READS / EXECUTIONS END AS AVG_DISK_READS          
, y.ELAPSED_TIME / 1000000 AS AVG_ELAPSED_TIME
, y.CPU_TIME / 1000000 AS AVG_CPU_TIME
FROM v$session x
, v$process z
, v$sql y
WHERE x.PADDR = z.ADDR AND x.SQL_ID = y.SQL_ID 
--AND Z.SPID = 'XXXX' 
--AND x.USERNAME='DEV'
AND x.STATUS = 'ACTIVE'
ORDER BY x.WAIT_TIME_MICRO desc;

3、剛剛執行過的SQL

如果是要查剛剛(由v$sqlarea存活時間而定)執行過的SQL中,哪些是比較耗資源的,可以試試下面這個:

SELECT *
FROM (SELECT EXECUTIONS
      , BUFFER_GETS / EXECUTIONS AS AVG_BUFFER_GETS
      , DISK_READS / EXECUTIONS AS AVG_DISK_READS          
      , ELAPSED_TIME / (EXECUTIONS*1000000) AS AVG_ELAPSED_TIME
      , CPU_TIME / (EXECUTIONS*1000000) AS AVG_CPU_TIME
      , SQL_TEXT
      , SQL_ID
      , SORTS / EXECUTIONS AS AVG_SORTS
      , SHARABLE_MEM
      , APPLICATION_WAIT_TIME / EXECUTIONS AS AVG_APPLICATION_WAIT_TIME
      , CONCURRENCY_WAIT_TIME / EXECUTIONS AS AVG_CONCURRENCY_WAIT_TIME
      , USER_IO_WAIT_TIME / EXECUTIONS AS AVG_USER_IO_WAIT_TIME
      , ROWS_PROCESSED
  FROM v$sqlarea
  WHERE EXECUTIONS > 0 AND PARSING_SCHEMA_NAME<>'SYS'
  AND LAST_ACTIVE_TIME BETWEEN to_date('2016-04-25 08:00:00','yyyy-mm-dd hh24:mi:ss') AND to_date('2017-07-25 12:00:00','yyyy-mm-dd hh24:mi:ss')
  ORDER BY AVG_ELAPSED_TIME DESC) x
WHERE ROWNUM < 100;

修改ORDER BY AVG_ELAPSED_TIME DESC 為其他欄位,比如 AVG_BUFFER_GETS就能查出哪些SQL的緩衝池讀比較高。

注意:v$sqlarea是在記憶體中的,此SQL的查詢時間範圍沒法太久遠。

4、過去七天內執行過的SQL

如果是要查最近7天內執行過的SQL中,哪些是比較耗資源的,那我們可以改用dba_hist_sqlstat進行查詢,它預設是儲存7/8天的。不過需要預先知道dbid、instance_number、snap_id這幾個資料,熟悉oracle的朋友應該清楚,awr報告的資料正是來源於此。

SELECT y.*,round(y.elap/y.exec,2) AS AVG_ELAP,z.SQL_TEXT FROM
(SELECT x.sql_id
, max (module) module
, sum (elapsed_time_delta)/ 1000000 elap
, sum (cpu_time_delta) cput
, sum (executions_delta) exec
FROM dba_hist_sqlstat x
WHERE x.dbid = 901548675 AND x.instance_number = 1 AND 5604 < x.snap_id AND x.snap_id <= 5612
AND x.MODULE = 'JDBC Thin Client'
GROUP BY x.sql_id)y
LEFT JOIN dba_hist_sqltext z ON y.sql_id = z.sql_id
WHERE y.exec >0
ORDER BY y.elap/y.exec DESC 

5、AWR報告

如果以上4種方式還不足以解君之憂的話,那麼還是來份AWR報告吧。

當然AWR報告也不是萬能的,比如報告中TOP SQL的排序是按照總資源消耗倒序排序的,假設某些SQL執行次數很少但是單次消耗資源很多的,那可能會被掩蓋掉而沒有在報告中展示出來。

至於AWR報告如何生成如何解讀,本篇不再贅述。

6、總結

以上介紹了幾種非專業DBA快速定位oracle TOP SQL的方式,希望於君有益。