2009. 2. 11. 16:16
[오라클] LOCK 문제를 일으키는 SQL 명령 찾기
2009. 2. 11. 16:16 in Oracle
LOCK 문제를 일으키는 SQL 명령 찾기 ---------------------------------- * 다음 Query는 Lock과 관련된 트랜잭션을 출력해준다. column username format a10 column sid format 999 column lock_type format a15 column MODE_HELD format a11 column MODE_REQUESTED format a10 column LOCK_ID1 format a8 column LOCK_ID2 format a8 select a.sid, decode(a.type, 'MR', 'Media Recovery', 'RT', 'Redo Thread', 'UN', 'User Name', 'TX', 'Transaction', 'TM', 'DML', 'UL', 'PL/SQL User Lock', 'DX', 'Distributed Xaction', 'CF', 'Control File', 'IS', 'Instance State', 'FS', 'File Set', 'IR', 'Instance Recovery', 'ST', 'Disk Space Transaction', 'IR', 'Instance Recovery', 'ST', 'Disk Space Transaction', 'TS', 'Temp Segment', 'IV', 'Library Cache Invalidation', 'LS', 'Log Start or Switch', 'RW', 'Row Wait', 'SQ', 'Sequence Number', 'TE', 'Extend Table', 'TT', 'Temp Table', a.type) lock_type, decode(a.lmode, 0, 'None', /* Mon Lock equivalent */ 1, 'Null', /* N */ 2, 'Row-S (SS)', /* L */ 3, 'Row-X (SX)', /* R */ 3, 'Row-X (SX)', /* R */ 4, 'Share', /* S */ 5, 'S/Row-X (SSX)', /* C */ 6, 'Exclusive', /* X */ to_char(a.lmode)) mode_held, decode(a.request, 0, 'None', /* Mon Lock equivalent */ 1, 'Null', /* N */ 2, 'Row-S (SS)', /* L */ 3, 'Row-X (SX)', /* R */ 4, 'Share', /* S */ 5, 'S/Row-X (SSX)', /* C */ 6, 'Exclusive', /* X */ to_char(a.request)) mode_requested, to_char(a.id1) lock_id1, to_char(a.id2) lock_id2 from v$lock a where (id1,id2) in (select b.id1, b.id2 from v$lock b where b.id1=a.id1 and b.id2=a.id2 and b.request>0) / ( 위의 Query를 실행시키면 다음과 같은 내용이 출력된다. ) SID LOCK_TYPE MODE_HELD MODE_REQUE LOCK_ID1 LOCK_ID2 --- --------------- ---------- ---------- -------- -------- 5 Transaction Exclusive None 262172 90 6 Transaction None Exclusive 262172 90 9 Transaction None Exclusive 262172 90 SID 6과 9는 SID 5가 걸고 있는 Lock이 풀리기를 기다리고 있음을 알 수 있다. * 다음 Query는 Lock과 관련된 테이블을 출력해 준다. column username format a10 column lockwait format a10 column sql_text format a80 column object_owner format a14 column object format a15 select b.username username, c.sid sid, c.owner object_owner, c.object object, b.lockwait, a.sql_text SQL from v$sqltext a, v$session b, v$access c where a.address=b.sql_address and a.hash_value=b.sql_hash_value and b.sid = c.sid and c.owner != 'SYS'; / ( 위의 Query를 실행하면 다음과 같은 결과가 출력된다. USERNAME SID OBJECT_OWNER OBJECT LOCKWAIT --------------- --- ------------- -------------- ---------- SQL --------------------------------------------------------------- LTO2 6 LTO EMP C3D320F4 update lto.emp set empno =25 where empno=7788 LTO3 9 LTO EMP C3D320C8 delete from lto.emp where empno=7788 LTO 5 LTO DEPT insert into lto.dept values (60,'PROGRAMMER','LOS ANGELOS') 여기서는 USERNAME에 나와있는 유저가 OBJECT에 나와있는 테이블을 수정하려고 함을 나타낸다. LT02,LT03는 LT0가 Commit,Rollback 하기를 기다리고 있음을 알 수 있다. 하지만 여기에는 가장 최근의 DML 명령 하나만 나와있기 때문에 여기 나온 명령이 반드시 Lock을 걸고 있는 명령이라고 단정지을 수는 없다. 관련된 프로세스 --------------- * 다음 Query를 실행해 보면 프로세스와 관련된 정보를 얻을 수 있다. column "ORACLE USER" format a11 column SERIAL# format 9999999 column "OS USER" format a8 select substr(s.username,1,11) "ORACLE USER", p.pid "PROCESS ID", s.sid "SESSION ID", s.serial#, osuser "OS USER", p.spid "PROC SPID",s.process "SESS SPID", s.lockwait "LOCK WAIT" from v$process p, v$session s, v$access a where a.sid=s.sid and p.addr=s.paddr and s.username != 'SYS' / * 위의 Query를 실행하면 다음과 같은 결과가 출력된다. ORACLE PROCESS SESSION SERIAL# OS USER PROC SESS LOCKWT USER ID ID SPID SPID ------ ------- ------- ------- ------- ---- ---- ------ LTO 19 5 31 usupport 17312 17309 LTO2 25 6 43 usupport 17313 17310 C3D320F4 LTO3 26 9 1 usupport 17314 17311 C3D320D8 이 때는 다음과 같이 조치한다. 1. LTO에게 Commit,Rollback 할 것을 요구한다. 2. SQLDBA>ALTER SYSTEM KILL SESSION '5,31'; 3. %kill -9 17309 (유닉스상의 Shadown Process) stop/id=(PROC SPID=SESS SPID on vms running single task) 여기서 SYS 유저는 제외시켰는데 필요하다면 Query의 Where 조건에서 s.username != 'SYS' 부분을 삭제하면 된다. CATBLOCK.SQL & UTLLOCKT.SQL --------------------------- $ORACLE_HOME/rdbms/admin 디렉토리에 있는 스크립트 가운데 catblock.sql과 utlockt.sql을 사용하여서 Lock 상황을 쉽게 파악할 수 있다. 이들은 다음과 같이 실행한다. %cd $ORACLE_HOME/rdbms/admin %sqldba lmode=y SQLDBA>connect internal SQLDBA>@catblock SQLDBA>@catproc 결과는 다음 Query 문으로 알아 본다. column waiting_session format a8 select lpad(' ',3*(level-1)) || waiting_session, lock_type, mode_requested, mode_held, lock_id1, lock_id1, lock_id2 from lock_holders connect by prior waiting_session = holding_session start with holding_session is null; 위의 Query에 의한 출력은 다음과 같다. WAITING_ LOCK_TYPE MODE_REQUE MODE_HELD LOCK_ID1 LOCK_ID2 -------- ----------------- ---------- ---------- ---------- ---------- 5 None 6 Transaction Exclusive Exclusive 262172 90 9 Transaction Exclusive Exclusive 262172 90 여기서 Session 6, Session 9가 Session 5를 기다리고 있음을 알 수 있다. Lock & Hanging 문제를 추정하는 방법 ----------------------------------- 프로그램 상에서 어느 부분이 Lock, Hanging 문제를 일으키는지 알아내기가 여의치 않을때 다음과 같은 방법을 사용해 보기 바란다. 1. init .ora의 sql_trace=ture로 세팅하면 연관된 SQL 명령이 출력될 것이다. 2. OS 상에서도 Process 상태를 점검하여 본다. 3. OS 상의 Debugging 기능을 사용하거나 만약 가능하다면 oradbx를 사용한다. Platform 에 따라서 없을 수도 있다. 4. 여러가지 Monitoring 방법과 Locking/Blocking 스크립트를 이용한다. PROCESS STACKS 확인 ------------------- 때로는 Hanging Process나 리소스를 점유하고 있는 Process의 Process Stack을 점검해 보는 것이 문제 해결에 도움이 되는 경우가 있다. 1. OS Debugging 프로그램을 이용하여 Hangup 되기 전의 마지막 Call을 확인 한다. ex)%truss -p 2. oradbx(오라클 debugging 프로그램)은 Support,Development 시에만 사용 된다. select substr(s.username,1,11) "ORACLE USER" , p.pid "PROCESS ID", s.sid "SESSION ID", s.serial#, osuser "OS USER", p.spid "PROC SPID" from v$session s, v$access a where a.sid=s.sid and p.addr=s.paddr and s.username != 'SYS' / 위의 Query를 실행하면 다음과 같은 결과가 출력된다. ORACLE PROCESS SESSION SERIAL# OS USER PROC SESS LOCKWT USER ID ID SPID SPID ------ ------- ------- ------- ------- ---- ---- ------ LTO 19 5 31 usupport 17312 17309 LTO2 25 6 43 usupport 17313 17310 C3D320F4 LTO3 26 9 1 usupport 17314 17311 C3D320D8 만약 oradbx가 없다면 다음과 같이 해서 만들어 준다. %cd $ORACLE_HOME/rdbms/lib %make -f oracle.mk oradbx LTO Process가 무엇을 하고 있는지 알고 싶으면 Process Stack을 보면 알수 있다. ps -ef | grep 17312 usupport 17312 17309 0 Sep 15 ? 0:00 oracleV713(DESCRIPTION=(LOCAL=YE type debug 17312 (이 유저의 oracle shadow process) dump stack dump procstat 위에서 생성된 트레이스 화일(user_dump_dest 에 생성됨)을 이용하면 Hanging 문제를 해결하는데 큰 도움이 된다. 자주 발생하는 LOCK 문제들 ------------------------- 1. Parent-Child 관계로 묶인 테이블에서 Child 테이블에 Index가 없는 상황 에서 Child 테이블을 수정하게 되면 Parent테이블에 TABLE LEVEL SHARE LOCK이 걸리게 되어서 Parent 테이블에 대한 모든 Update가 금지된다. 2. 블럭의 PCTFREE가 매우 작다면 한 블럭에 여러개의 레코드가 들어 있기 때문에 한 블럭에 과도한 트랜잭션이 들어와서 블럭의 Transaction Layer가 Release 되기를 기다리게 되는 경우도 있다. Ex) create table test (a number) initrans 1 maxtrans 1; SYSTEM: insert into test values (5); /* completed */ SCOTT: insert into SYSTEM.test values (10); /* Scott waits */ SID OWNER LOCK_TYPE MODE_HELD MODE_REQUE LOCK_ID1 LOCK_ID2 ---- ----- ------------- ----------- ---------- -------- -------- 7 System Transaction Exclusive None 196639 54 10 Scott Transaction None Share 196639 54
[출처] http://www.ihelpers.co.kr/programming/tipntech.php?CMD=view&TYPE=6&KEY=&SC=S&&CC=&PAGE=1&IDX=408