如何查詢Oracle性能監控


轉摘:http://www.cnblogs.com/preftest/archive/2010/11/14/1876856.html

1、監控等待事件
select event,sum(decode(wait_time,0,0,1)) prev, sum(decode(wait_time,0,1,0)) curr,count(*)
from v$session_wait
group by event order by 4;

Lock wait occur when a session attempts to acquire a lock that is already held by another session. A session will be blocked until the blocking session releases the lock. Locks are designed to ensure data integrity by limiting simultaneous data access.

Multi-user database locking generally consists of two levels: exclusive locks and share locks. You want to watch out for exclusive locks (that is, TX) as they prohibit resource sharing. For example, the first transaction that exclusively locks a resource is the only one that can alter the resource (except for the DBA) until the exclusive lock is released. Share locks, unlike exclusive locks, allow a resource to be shared.

Deadlocking is commonly seen in multi-user systems. It typically occurs when all the hung users are waiting to access a table that another user has locked. This situation causes a deadlock, because each user (transaction) is waiting for resources to be freed by the other user (the blocker). Often, many developers attempt to update the same table and many users attempting to update or select from the same table.

Most locking issues are application-specific and can be addressed by tuning the concurrency logic in the application.

也可利用v$system_event視圖執行下面的查詢查看數據庫中某些常見的等待事件:
select * from v$system_event
where event in ('buffer busy waits',
'db file sequential read',
'db file scattered read',
'enqueue',
'free buffer waits',
'latch free',
'log file parallel write',
'log file sync',
'enq: TX - row lock contention');

接着,利用下面對v$session_event和v$session視圖進行的查詢,研究具有對上面顯示的內容有貢獻的等待事件的會話:
select se.sid,s.username,se.event,se.total_waits,se.time_waited,se.average_wait
from v$session s,v$session_event se
where s.sid = se.sid
and se.event not like 'SQL*Net%'
and s.status = 'ACTIVE'
and s.username is not null;

還可以組合v$session和v$session_wait視圖進行查詢:
select sw.sid,s.username,sw.event,sw.wait_time,sw.state,sw.seconds_in_wait SEC_IN_WAIT
from v$session s,v$session_wait sw
where s.sid = sw.sid
and sw.event not like 'SQL*Net%'
and s.username is not null
order by sw.wait_time desc;

查詢具體會話等待事件的詳細信息
select sid,event,p1text,p1,p2text,p2,p3text,p3
from v$session_wait
where sid between &1 and &2
and event not like '%SQL%'
and event not like '%rdbms%';

在查出會話執行了什么SQL語句發生等待事件:
select s1.sid,s1.event,s2.sql_text
from v$session s1,v$sql s2
where s1.sid = &sid_in
and s1.event in('enq: TX - row lock contention')
and s1.SQL_ID = s2.sql_id ;

 


2、監控表空間的I/O比例:
select df.tablespace_name name,df.file_name "file",f.phyrds pyr,f.phyblkrd pbr,f.phywrts pyw,
f.phyblkwrt pbw
from v$filestat f,dba_data_files df
where f.file#=df.file_id

診斷:
If the number of physical block reads is significantly higher than the number of physical reads, this is an indication that the indexes on these tables may need to be reviewed, or there may be full table scans being performed on the tables within the tablespace.  In general, if the number of block reads is equal to the number of reads, the tables in the tablespace were being accessed by a ROWID, requiring the database to read only one data block.  

If one of the data files is getting a majority of the reads and writes, you may be able to improve performance by creating multiple data files on seperate disks or by striping the data file across multiple disks.

 


3、查詢是否有長時間的操作
同時滿足以下幾個條件,操作信息才會出現在V$SESSION_LONGOPS中:
1)、操作是以下幾種操作之一
# Table scan;
# Index Fast Full Scan;
# Hash join;
# Sort/Merge;
# Sort Output;
# Rollback;
# Gather Table's Index Statistics
2)、操作時間大於6秒
3)、讀取的block數目大於一定量
如果是TABLE FULL SCAN,讀取的block數目至少大於10000
如果是Index Fast Full Scan,讀取的block數目至少大於1000
其他操作讀取block的數目不明


實驗:
create table tt as select * from all_objects;

commit;

Set timing on;

select * from tt order by 1,2,3,4;


用以下語句找出長時間操作的SQL語句:
select longops.sid,longops.elapsed_seconds,longops.opname,sql.sql_text from
 v$session_longops longops , v$sql sql where longops.elapsed_seconds>6 and longo
ps.sql_id=sql.sql_id;

或者:
SELECT SE.SID,
 OPNAME,
 TRUNC(SOFAR / TOTALWORK * 100, 2) || '%' AS PCT_WORK,
 ELAPSED_SECONDS ELAPSED,
 ROUND(ELAPSED_SECONDS * (TOTALWORK - SOFAR) / SOFAR) REMAIN_TIME,
 SQL_TEXT
 FROM V$SESSION_LONGOPS SL, V$SQLAREA SA, V$SESSION SE
 WHERE SL.SQL_HASH_VALUE = SA.HASH_VALUE
 AND SL.SID = SE.SID
 AND SOFAR != TOTALWORK
 ORDER BY START_TIME
;


調整PGA優化排序:
首先查看Oracle的v$pga_target_advice:
SELECT ROUND(pga_target_for_estimate/1024/1024) AS target_mb,
 estd_pga_cache_hit_percentage AS hit_ratio,
 estd_overalloc_count
FROM v$pga_target_advice
ORDER BY target_mb;
然后調整PGA
alter system set pga_aggregate_target=150M;

在OLTP系統中,典型PGA內存設置應該是總內存的較小部分(例如20%),剩下80%分配給SGA。
OLTP:PGA_AGGREGATE_TARGET = (total_mem * 80%) * 20%
在DSS系統中,由於會運行一些很大的查詢,典型的PGA內存最多分配70%的內存。
DSS:PGA_AGGREGATE_TARGET = (total_mem * 80%) * 50%

Oracle的排序操作:
服務器首先在sort_area_size指定大小的內存區域里排序,如果所需的空間超過sort_area_size,排序會在臨時表空間里進行。在專用服務器模式下,排序空間在PGA中,在共享服務器模式下,排序空間在UGA中。如果沒有建立large pool,UGA處於shared pool中,如果建立了large pool,UGA就處於large pool中,而PGA不在sga中,它是與每個進程對應單獨存在的。
PGA:program global area,為單個進程(服務器進程或后台進程)保存數據和控制信息的內存區域。PGA與進程一一對應,且只能被起對應的進程讀寫,PGA在用戶登錄數據庫創建會話的時候建立。

排序診斷1:
Select * from v$sysstat where name like '%sort%';
--Sort(disk):要求IO去臨時表空間的排序數目
--Sort(memory):完全在memory中完成的排序數目
--Sort(rows):被排序的行數合計
Sort(disk)/ Sort(memory)<5%, 如果超過5%,增加sort_area_size的值(調整PGA)。

SELECT disk.Value disk,mem.Value mem,(disk.Value/mem.Value)*100 ratio
FROM v$sysstat disk,v$sysstat mem
WHERE mem.NAME='sorts (memory)' AND disk.NAME='sorts (disk)';


*排序操作需要大量CPU時間和內存
Oracle的排序過程分析:
當待排序數據集不是很大時,服務器在內存(排序區)完成排序操作,如果排序需要更過的內存空間,服務器將進行如下處理:
(1)將數據分成多個小的集合,對每一集合進行排序
(2)服務器向磁盤申請臨時空間,將排好序的中間結果寫入臨時段,再對另外的集成進行排序。
(2)在所有的集合均排好序后,服務器再將它們進行合並得到最終的結果,如果排序區尺寸太小,合並無法一次完成時,將分多次進行。


排序診斷2(監控臨時表空間的使用情況及其配置):
Select tablespace_name,current_users,total_extents,
used_extents,extent_hits,max_used_blocks,max_sort_blocks
FROM v$sort_segment;

CURRENT_USERS: Number of active users
TOTAL_EXTENTS: Total number of extents
USED_EXTENTS: Extents currently allocated to sorts
EXTENT_HITS: Number of times an unused extent was found in the pool
MAX_USED_BLOCKS: Maximum number of used blocks
MAX_SORT_BLOCKS: Maximum number of blocks used by an individual sort

臨時表空間的配置:
A、initial/next設置為sort_area_size的整數倍,允許額外的一個block作為segment的header
B、pctincrease=0
C、基於不同的排序需要建立多個臨時表空間
D、將臨時表空間文件分散到多個磁盤上
 

 

 

4、臨時表空間使用的監控

如果大量排序操作發生,就有可能動用到臨時表空間

通過動態性能視圖v$sort_usage還可以查詢使用排序段的用戶與會話信息:
select username,segtype,segfile#,segblk#,extents,segrfno# from v$sort_usage;

從segfile#可以找到動用了哪個表空間:
select tm.file# Fnum ,tf.tfafn AFN,tm.name FName from v$tempfile tm,x$kcctf tf where tm.file# = tf.tfnum;

參考:
http://www.eygle.com/archives/2006/03/tempfile_and_sort_usage.html


如果程序中使用了臨時的LOB類型變量,Oracle會分配臨時空間,如果並發很高,初始區很大,那么數據庫可能產生嚴重的TEMP表空間的不足問題.
可以通過測試輕易再現這種狀況,在多個Session中執行如下代碼:
declare
  A CLOB;
BEGIN
  A:='ABC';
  DBMS_LOCK.SLEEP(120);
END;

查詢v$sort_usage視圖,可以獲得臨時表空間的使用情況(哪個用戶、哪個Session因為什么原因使用了多少臨時表空間):
select s.username, s.sid, u.tablespace, u.contents, u.segtype,
round(u.blocks*8192/1024/1024,2) MB
from v$session s, v$sort_usage u
where s.saddr = u.session_addr
and u.contents = 'TEMPORARY'
order by MB DESC ;

SEGTYPE=SORT的是因為排序而用到臨時表空間的。
SEGTYPE=LOB_DATA是因為使用了臨時的LOB類型變量而用到臨時表空間的。

參考:
http://www.eygle.com/archives/2006/03/lob_and_temporary_tablespace.html

實驗:
SQL> select max(sid) from v$mystat;
 
  MAX(SID)
----------
        45
 
SQL> DECLARE
  2  a clob;
  3  BEGIN
  4  dbms_lob.createtemporary(a, TRUE,dbms_lob.call);
  5  dbms_lob.freetemporary(a);
  6  END;
  7  /
 
PL/SQL procedure successfully completed.
 
SQL> select count(*) from dual;
 
  COUNT(*)
----------
         1
 
SQL> SELECT se.inst_id,
  2         se.username username,
  3         se.SID sid,
  4         se.status status,
  5         se.sql_hash_value,
  6         se.prev_hash_value,
  7         su.TABLESPACE tablespace,
  8         su.segtype,
  9         su.CONTENTS CONTENTS,
 10         round(su.blocks * 8192 / 1024 / 1024, 2) MB
 11  FROM gv$session se,
 12       gv$sort_usage su
 13  WHERE se.saddr=su.session_addr
 14  AND   se.inst_id=su.inst_id
 15  ORDER BY MB;
 
INST_ID USERNAME SID STATUS SQL_HASH_VALUE PREV_HASH_VALUE TABLESPACE SEGTYPE  CONTENTS  MB
------- -------- --- ------ -------------- --------------- ---------- -------- --------- --
      1 SYS       45 INACTI      317853294       317853294 TEMP       LOB_DATA TEMPORARY  1

此時CLOB占用的TEMP空間不會自動釋放,需要等待會話斷開,才能釋放。但這個空間,在本會話中,還是可以重用的,只是不供其它會話使用。

在10.2.0.3以前,只能讓會話退出,以釋放這部份空間,在10.2.0.4中當作一個BUG(Bug:5723140)來修復,但默認不激活,需要通過設置60025事件才可以釋放這些lob的TEMP空間。
參考:
http://www.dbaroad.me/archives/2009/09/lob_temp.html


LOB類型變量:
數據庫中提供了兩種字段類型 Blob 和 Clob 用於存儲大型字符串或二進制數據(如圖片)。 Blob 采用單字節存儲,適合保存二進制數據,如圖片文件。 Clob 采用多字節存儲,適合保存大型文本數據。


臨時表空間優化:
(一)、創建用戶時要記得為用戶創建臨時表空間。
(二)、合理設置PGA,減少臨時表空間使用的幾率。
(三)、要為臨時表空間保留足夠的硬盤空間。
參考:
http://database.51cto.com/art/200907/132965.htm


查看臨時表空間占用率:
select * from v$temp_space_header;

重建臨時表空間的方法:
Temporary tablespace是不能直接drop默認的臨時表空間的,不過我們可以通過以下方法達到。
查看目前的Temporary Tablespace
SQL> select name from v$tempfile;

NAME
———————————————————————
D:\ORACLE\ORADATA\ORCL\TEMP01.DBF

SQL> select username,temporary_tablespace from dba_users;
USERNAME TEMPORARY_TABLESPACE
------------------------------ ------------------------------
MGMT_VIEW TEMP
SYS TEMP
SYSTEM TEMP
DBSNMP TEMP
SYSMAN TEMP

創建中轉臨時表空間
create temporary tablespace TEMP1 TEMPFILE 'D:\ORACLE\ORADATA\ORCL\temp02.DBF' SIZE 512M REUSE AUTOEXTEND ON NEXT 1M MAXSIZE UNLIMITED;
改變缺省臨時表空間 為剛剛創建的新臨時表空間temp1
alter database default temporary tablespace temp1;
刪除原來臨時表空間
drop tablespace temp including contents and datafiles;
重新創建臨時表空間
create temporary tablespace TEMP TEMPFILE 'D:\ORACLE\ORADATA\ORCL\temp01.DBF' SIZE 512M REUSE AUTOEXTEND ON NEXT 1M MAXSIZE UNLIMITED;
重置缺省臨時表空間為新建的temp表空間
alter database default temporary tablespace temp;
刪除中轉用臨時表空間
drop tablespace temp1 including contents and datafiles;

以上的方法只是暫時釋放了臨時表空間的磁盤占用空間,是治標但不是治本的方法,真正的治本的方法是找出數據庫中消耗資源比較大的sql語句,然后對其進行優化處理。
參考:
http://lanmh.javaeye.com/blog/643676

 

 

5、監控LibraryCache
SELECT (SUM(PINS - RELOADS)) / SUM(PINS) "LIB CACHE" FROM V$LIBRARYCACHE;

SELECT (SUM(GETS - GETMISSES - USAGE - FIXED)) / SUM(GETS) "ROW CACHE" FROM V$ROWCACHE;

SELECT SUM(PINS) "EXECUTIONS", SUM(RELOADS) "CACHE MISSES WHILE EXECUTING" FROM V$LIBRARYCACHE;

后者除以前者,此比率小於1%,接近0%為好。
SELECT SUM(GETS) "DICTIONARY GETS",SUM(GETMISSES) "DICTIONARY CACHE GET MISSES"
FROM V$ROWCACHE

查找不能被充分共享利用的SQL語句(查詢LibraryCache中執行次數偏低的SQL語句):
SELECT sql_text FROM v$sqlarea WHERE executions < 5 ORDER BY UPPER(sql_text);

查找SQL執行次數和SQL解釋次數(hard parse),對比兩個值的差:
SELECT sql_text , parse_calls , executions FROM v$sqlarea ORDER BY parse_calls;

查詢v$librarycache視圖的Reloads值(reparsing)的值,值應該接近0,否則應該考慮調整shared pool size
invalidations的值也應該接近0
select namespace,gethitratio,pinhitratio,reloads,invalidations from v$librarycache;

重點關注SQL的命中率:
SELECT gethitratio FROM v$librarycache WHERE namespace = 'SQL AREA';
查看指定某條SQL語句的執行情況(執行次數、加載次數等):
SELECT sql_text , users_executing , executions , loads FROM v$sqlarea where sql_text like 'select * from hr.tt';

*SQL語句運行過程
1).使用hash算法得到sql語句的hash_value值
2).如果hash_value值在內存中,叫做命中執行軟解析
3).如果hash_value值不存在,執行硬解析
4).語法解析,查看是否有錯誤
5).語意解析,查看權限是否符合
6).若有視圖,取出視圖的定義
7).進行sql語句的自動改寫,如將子查詢改寫為連接
8).選擇最優的執行計划
9).變量綁定
10).運行執行計划
11).返回結果給用戶
因為軟解析是從此11步驟中第9步開始的,因此軟解析比硬解析節約大量的系統開銷,應該盡量降低硬解析的次數


診斷:
1) 檢查v$librarycache中sql area的gethitratio是否超過90%,如果未超過90%,應該檢查應用代碼,提高應用代碼的效率:
Select gethitratio from v$librarycache where namespace='SQL AREA';
2) v$librarycache中reloads/pins的比率應該小於1%,如果大於1%,應該增加參數shared_pool_size的值:
Select sum(pins) "executions", sum(reloads) "cache misses",sum(reloads)/sum(pins) from v$librarycache;
reloads/pins>1%有兩種可能,一種是library cache空間不足,一種是sql中引用的對象不合法。
3)查看某個session的hard parse個數:
select a.sid,a.value from v$sesstat a,v$session b ,v$statname c where a.sid=b.sid and a.statistic#=c.statistic# and a.sid = 137 and c.name='parse count (hard)';


調優方法:
1)、調整shared_pool_size
SELECT shared_pool_size_for_estimate AS pool_size,estd_lc_size,estd_lc_time_saved FROM v$shared_pool_advice;

Alter System set shared_pool_size=120M;

2)、書寫程序是盡量使用變量不要過多的使用常量
實驗:
創建表格
SQL>CREATE TABLE  m(x int);
創建存儲過程proc1,使用綁定變量
SQL>CREATE OR REPLACE PROCEDURE proc1
AS
BEGIN
  FOR i IN 1..10000
  LOOP
Execute immediate
  'INSERT INTO m VALUES(:x)' USING i;
  END LOOP;
END;
/
創建存儲過程proc2,不使用綁定變量
SQL>CREATE OR REPLACE PROCEDURE proc2
AS
BEGIN
  FOR i IN 1..10000
  LOOP
Execute immediate
  'INSERT INTO m VALUES('||i||')' ;
  END LOOP;
END;
/
執行proc2和proc1,對比執行效率
SQL>SET TIMING ON
SQL> exec proc2;
PL/SQL procedure successfully completed.
Elapsed: 00:00:08.93
SQL> select count(*) from m;
  COUNT(*)
----------
     10000
Elapsed: 00:00:00.01
SQL> TRUNCATE TABLE m;
Table truncated.
Elapsed: 00:00:01.76
SQL> exec proc1;
PL/SQL procedure successfully completed.
Elapsed: 00:00:01.85
SQL> select count(*) from m;
  COUNT(*)
----------
     10000
Elapsed: 00:00:00.00

3)、修改cursor_sharing參數為similar,讓類似的SQL語句不做hard parse:
有時候我們的應用程序沒有使用綁定變量,而修改程序可能有點困難,我們可能需要設置CURSOR_SHARING=SIMILAR來強制ORACLE使用綁定變量。
Show parameter cursor
Alter system set cursor_sharing=SIMILAR
參考:
http://blog.csdn.net/biti_rainy/archive/2004/07/12/39466.aspx
http://space.itpub.net/519536/viewspace-562987
http://wiki.oracle.com/page/CURSOR_SHARING
實驗:
SQL> show parameter cursor_sharing
 cursor_sharing string EXACT
SQL> select * from test where object_id=1;
no rows selected
SQL> select sql_text,parse_calls from v$sqlarea where sql_text like 'select * from test%';
select * from test where object_id=:"SYS_B_0" 2
select * from test where object_id=1 1
SQL> alter system flush shared_pool;
System altered.
SQL> alter system flush shared_pool;
System altered.
SQL> alter session set cursor_sharing=similar; ----second
Session altered.
SQL> select * from test where object_id=1;
no rows selected
SQL> select sql_text,parse_calls from v$sqlarea where sql_text like 'select * from test%';
select * from test where object_id=:"SYS_B_0" 1
SQL> select * from test where object_id=2;
no rows selected
SQL> select sql_text,parse_calls from v$sqlarea where sql_text like 'select * from test%';
select * from test where object_id=:"SYS_B_0" 2

4)、大對象保留
查找沒有保存在library cache中的大對象:
Select * from v$db_object_cache where sharable_mem>10000 and type in ('PACKAGE','PROCEDURE','FUNCTION','PACKAGE BODY') and kept='NO';
將這些對象保存在library cache中:
Execute dbms_shared_pool.keep('package_name');
對應腳本:dbmspool.sql

參考:
http://database.51cto.com/art/201004/194003.htm

 

 

6、找使用CPU多的用戶session
select a.sid,spid,status,substr(a.program,1,40) prog,a.terminal,osuser,value/60/100 value
from v$session a,v$process b,v$sesstat c
where c.statistic#=12 and c.sid=a.sid and a.paddr=b.addr order by value desc;
*12是cpu used by this session

再找出使用CPU多的SQL語句:
查找指定SPID正在執行的SQL語句:
SELECT P.pid pid,S.sid sid,P.spid spid,S.username username,
S.osuser osname,P.serial# S_#,P.terminal,P.program  program,
P.background,S.status,RTRIM(SUBSTR(a.sql_text, 1, 80))  SQL
FROM v$process P, v$session S,v$sqlarea A WHERE P.addr = s.paddr
AND S.sql_address = a.address (+)  AND P.spid LIKE '%&1%';

*在linux環境可以通過ps查看進程信息包括pid,windows中任務管理器的PID與v$process中pid不能一一對應。windows是多線程服務器,每個進程包含一系列線程。這點於unix等不同,Unix每個Oralce進程獨立存在,在Nt上所有線程由Oralce進程衍生。

指定SID查看正在執行的SQL語句:
SELECT P.pid pid,S.sid sid,P.spid spid,S.username username,
S.osuser osname,P.serial# S_#,P.terminal,P.program  program,
P.background,S.status,RTRIM(SUBSTR(a.sql_text, 1, 80))  SQL
FROM v$process P, v$session S,v$sqlarea A WHERE P.addr = s.paddr
AND S.sql_address = a.address (+)  AND s.sid = '136';

 

7、回滾段的爭用情況:
select name,waits,gets,waits/gets ratio from v$rollstat a,v$rollname b where a.usn=b.usn;

對含有回滾段塊的緩沖區的爭用也會影響到對回滾段的爭用。這可以通過查詢動態性能表V$WAITSTAT來檢測是否存在對回滾段的爭用,例如:
SELECT class,count FROM V$WAITSTAT 
WHERE class IN('system undo header','system undo block','undo header','undo block');
其中參數含義如下:
◆ system undo header:對含有SYSTEM回滾段標題塊的緩沖區的等待次數。
◆ system undo block:對含有SYSTEM回滾段非標題塊的緩沖區的等待次數。
◆ undo header:對含有非SYSTEM回滾段標題塊的緩沖區的等待次數。
◆ undo block:對含有非SYSTEM回滾段非標題塊的緩沖區的等待次數。

如果任何等待次數大於總請求數的1%,則應創建更多的回滾段來減少競爭,可以周期性地檢查這些統計數字,並將它與總的請求數據的次數作比較。總的請求數據次數可用如下語句求出:
SELECT SUM(value) FROM V$SYSSTAT 
WHERE name IN('db block gets','consistent gets');

8.查詢 Buffer 命中率

 select 1 - ((physical.value - direct.value - lobs.value) / logical.value)
"Buffer Cache Hit Ratio"
from v$sysstat physical,v$sysstat direct,v$sysstat lobs,v$sysstat logical
where physical.name = 'physical reads'
and direct.name='physical reads direct'
and lobs.name='physical reads direct (lob)'
and logical.name='session logical reads';

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM