阻塞是DBA經(jīng)常碰到的情形,尤其是不良的應(yīng)用程序設(shè)計(jì)的阻塞將導(dǎo)致性能嚴(yán)重下降直至數(shù)據(jù)庫(kù)崩潰。對(duì)DBA而言,有必要知道如何定位到當(dāng)前系統(tǒng)有哪些阻塞,到底誰(shuí)是阻塞者,誰(shuí)是被阻塞者。本文對(duì)此給出了描述并做了相關(guān)演示。
a、INSERT阻塞主要是由于有一個(gè)帶主鍵的表,或者表上有惟一的約束,在兩個(gè)會(huì)話試圖用同樣的值插入一行時(shí)引發(fā)阻塞。多表通過(guò)引用完整性約束相互鏈接時(shí),在其依賴的父表正在創(chuàng)建或刪除期間,對(duì)子表的插入可能會(huì)阻塞。對(duì)于該類情形建議使用序列來(lái)生成主鍵/惟一列值。
b、對(duì)于UPDATE、DELETE、MERGE 和SELECT FOR UPDATE阻塞,只要有任一session使用這些操作已經(jīng)鎖定行,其余的必須處于等待狀態(tài)。直到當(dāng)前鎖定行上的鎖(排他鎖)釋放。對(duì)于該類情形,建議盡可能快速提交事務(wù),或采用批量SQL方式提交。
c、對(duì)于一個(gè)阻塞的SELECT FOR UPDATE,解決方案很簡(jiǎn)單:只需增加NOWAIT 子句,它就不會(huì)阻塞了。
robin@SZDB:~/dba_scripts/custom/sql> more my_env.sql
SELECT spid, s.sid, s.serial#, p.username, p.program
FROM v$process p, v$session s
WHERE 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$sqlarea
SELECT '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.address
ORDER 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$lock
SELECT 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.id2
FROM v$session sn, v$lock m
WHERE (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.sql
set linesize 190
col osuser format a15
col username format a20 wrap
col object_name format a20 wrap
col terminal format a25 wrap
col Req_Mode format a20
select 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 C
where A.OBJECT_ID(+) = B.ID1
and B.SID = C.SID
and C.USERNAME is not null
order by B.SID, B.ID2;