阻塞是DBA經常碰到的情形,尤其是不良的應用程式設計的阻塞將導致效能嚴重下降直至資料庫崩潰。對DBA而言,有必要知道如何定位到當前系統有哪些阻塞,到底誰是阻塞者,誰是被阻塞者。本文對此給出了描述並做了相關示範。
a、INSERT阻塞主要是由於有一個帶主鍵的表,或者表上有惟一的約束,在兩個會話試圖用同樣的值插入一行時引發阻塞。多表通過參考完整性約束相互連結時,在其依賴的父表正在建立或刪除期間,對子表的插入可能會阻塞。對於該類情形建議使用序列來產生主鍵/惟一列值。
b、對於UPDATE、DELETE、MERGE 和SELECT FOR UPDATE阻塞,只要有任一session使用這些操作已經鎖定行,其餘的必須處於等待狀態。直到當前鎖定行上的鎖(獨佔鎖定)釋放。對於該類情形,建議儘可能快速提交事務,或採用批量SQL方式提交。
c、對於一個阻塞的SELECT FOR UPDATE,解決方案很簡單:只需增加NOWAIT 子句,它就不會阻塞了。
robin@SZDB:~/dba_scripts/custom/sql> more my_env.sql SELECT spid, s.sid, s.serial#, p.username, p.programFROM v$process p, v$session sWHERE p.addr = s.paddr AND s.sid = (SELECT sid FROM v$mystat WHERE rownum = 1);robin@SZDB:~/dba_scripts/custom/sql> more blocker.sql col block_msg format a50; select c.terminal||' ('''||a.sid||','||c.serial#||''') is blocking '||b.sid||','||d.serial# block_msg, a.block from v$lock a,v$lock b,v$session c,v$session d where a.id1=b.id1 and a.id2=b.id2 and a.block>0 and a.sid <>b.sid and a.sid=c.sid and b.sid=d.SID; robin@SZDB:~/dba_scripts/custom/sql> more blocking_session_detail.sql--To find the query for blocking session--Access Privileges: SELECT on v$session, v$sqlareaSELECT 'sid=' || a.SID || ' Wait Class=' || a.wait_class || ' Time=' || a.seconds_in_wait || CHR (10) || ' Query=' || b.sql_text FROM v$session a, v$sqlarea b WHERE a.blocking_session IS NOT NULL AND a.sql_address = b.addressORDER BY a.blocking_session/robin@SZDB:~/dba_scripts/custom/sql> more request_lock_type.sql--This script generates a report of users waiting for locks.--Access Privileges: SELECT on v$session, v$lockSELECT sn.username, m.sid, m.type, DECODE(m.lmode, 0, 'None', 1, 'Null', 2, 'Row Share', 3, 'Row Excl.', 4, 'Share', 5, 'S/Row Excl.', 6, 'Exclusive', lmode, ltrim(to_char(lmode,'990'))) lmode, DECODE(m.request,0, 'None', 1, 'Null', 2, 'Row Share', 3, 'Row Excl.', 4, 'Share', 5, 'S/Row Excl.', 6, 'Exclusive', request, ltrim(to_char(m.request, '990'))) request, m.id1, m.id2FROM v$session sn, v$lock mWHERE (sn.sid = m.sid AND m.request != 0) OR (sn.sid = m.sid AND m.request = 0 AND lmode != 4 AND (id1, id2) IN (SELECT s.id1, s.id2 FROM v$lock s WHERE request != 0 AND s.id1 = m.id1 AND s.id2 = m.id2) )ORDER BY id1, id2, m.request; robin@SZDB:~/dba_scripts/custom/sql> more request_lock_detail.sqlset linesize 190col osuser format a15col username format a20 wrapcol object_name format a20 wrapcol terminal format a25 wrapcol Req_Mode format a20select B.SID, C.USERNAME, C.OSUSER, C.TERMINAL, DECODE(B.ID2, 0, A.OBJECT_NAME, 'Trans-'||to_char(B.ID1)) OBJECT_NAME, B.TYPE, DECODE(B.LMODE,0,'--Waiting--', 1,'Null', 2,'Row Share', 3,'Row Excl', 4,'Share', 5,'Sha Row Exc', 6,'Exclusive', 'Other') "Lock Mode", DECODE(B.REQUEST,0,' ', 1,'Null', 2,'Row Share', 3,'Row Excl', 4,'Share', 5,'Sha Row Exc', 6,'Exclusive', 'Other') "Req_Mode" from DBA_OBJECTS A, V$LOCK B, V$SESSION Cwhere A.OBJECT_ID(+) = B.ID1 and B.SID = C.SID and C.USERNAME is not nullorder by B.SID, B.ID2;