Beruflich Dokumente
Kultur Dokumente
https://damir-vadas.blogspot.com/2009/11/blocking-session-detect-unblock-notify.html
/* ---------------------------------------------------------------------------
Filename: sb.sql
CR/TR# :
Purpose : Find blocking sessions and create release statements for RAC and non
RAC environment
Date : 08.07.2005.
Author : Damir Vadas
set serveroutput on
set linesize 266
set pagesize 600
set trimout on
declare
cursor c_blockers IS
SELECT DISTINCT
username blocker_user,
gvb.sid,
gvs.serial# serial,
gvb.inst_id,
gvb.ctime ,
module,
decode(gvb.type, 'MR', 'Media_recovery',
'RT', 'Redo_thread',
'UN', 'User_name',
'TX', 'Transaction',
'TM', 'Dml',
'UL', 'PLSQL User_lock',
'DX', 'Distrted_Transaxion',
'CF', 'Control_file',
'IS', 'Instance_state',
'FS', 'File_set',
'IR', 'Instance_recovery',
'ST', 'Diskspace Transaction',
'IV', 'Libcache_invalidation',
'LS', 'LogStaartORswitch',
'RW', 'Row_wait',
'SQ', 'Sequence_no',
'TE', 'Extend_table',
'TT', 'Temp_table',
'Nothing-'
) lock_type,
action
FROM gv$lock gvb, gv$lock gvw, gv$session gvs
WHERE (gvb.id1, gvb.id2) in (
SELECT id1, id2 FROM gv$lock WHERE request=0
INTERSECT
SELECT id1, id2 FROM gv$lock WHERE lmode=0
)
AND gvb.id1=gvw.id1
AND gvb.id2=gvw.id2
AND gvb.request=0
AND gvw.lmode=0
AND gvb.sid=gvs.sid
AND gvb.inst_id=gvs.inst_id
ORDER BY CTIME desc
;
CURSOR c_w IS
SELECT gvw.sid waiter_sid,
gvw.inst_id waiter_inst_id
FROM gv$lock gvb, gv$lock gvw, gv$session gvs
WHERE (gvb.id1, gvb.id2) in (
SELECT id1, id2 FROM gv$lock WHERE request=0
INTERSECT
SELECT id1, id2 FROM gv$lock WHERE lmode=0
)
AND gvb.id1=gvw.id1
AND gvb.id2=gvw.id2
AND gvb.request=0
AND gvw.lmode=0
AND gvb.sid=gvs.sid
AND gvb.inst_id=gvs.inst_id
ORDER BY gvb.CTIME desc
;
i NUMBER := 0;
bHasAny boolean;
bOnTheSameNode boolean;
l_inst_id BINARY_INTEGER := 0;
v_sid number := 0;
v_serial NUMBER := 0;
v_instance BINARY_INTEGER := 0;
db_ver VARCHAR2(128);
db_ver2 VARCHAR2(128);
s_job_command VARCHAR2 (256);
s VARCHAR2(1024);
PROCEDURE kill_by_hand is
BEGIN
DBMS_OUTPUT.PUT_LINE (chr(9)||'ALTER SYSTEM DISCONNECT SESSION
'''||v_sid||','||v_serial||''' IMMEDIATE;');
DBMS_OUTPUT.PUT_LINE (chr(9)||'ALTER SYSTEM KILL SESSION
'''||v_sid||','||v_serial||''' IMMEDIATE;');
END;
begin
DBMS_OUTPUT.ENABLE(200000);
dbms_utility.db_version(db_ver,db_ver2);
DBMS_OUTPUT.PUT_LINE('Oracle version: '||db_ver|| ' ('||db_ver2||')');
DBMS_OUTPUT.PUT_LINE (chr(9));
bHasAny := FALSE;
bOnTheSameNode := FALSE;
FOR v_blockers in c_blockers loop
bHasAny := TRUE;
IF (i=0) THEN
select instance_number into l_inst_id from v$instance;
bOnTheSameNode := (v_blockers.inst_id=l_inst_id);
DBMS_OUTPUT.PUT_LINE (rpad('Blocker',12,'
')||' '||' Inst '||rpad('SID',6,' ')||' '||rpad('Serial',6,'
')||' '||' '||rpad('[sec]',6,' ')||' '||
lpad('Lock Type',10,' ')||' '|| lpad('Module',13,' ')
);
dbms_output.put_line(rpad('-',120,'-'));
END IF;
v_sid := v_blockers.sid;
v_serial := v_blockers.serial;
v_instance := v_blockers.inst_id ;
DBMS_OUTPUT.PUT_LINE(LPAD(to_char(i+1),3,' ')||'.
'||rpad(v_blockers.blocker_user,12,' ')||' '||rpad(v_blockers.inst_id,4,'
')||' '||rpad(v_blockers.SID,8,' ' )||' '||lpad(v_blockers.serial,5,'
')||' '||lpad(v_blockers.CTIME,7,' ')||' '||
lpad(v_blockers.lock_type,13,' ')||lpad(v_blockers.module,15,' ')
);
FOR v_w in c_w LOOP
FOR v_waiters IN c_waiters (v_w.waiter_sid,v_w.waiter_inst_id) LOOP
DBMS_OUTPUT.PUT_LINE (lpad(chr(9),1)||rpad(v_waiters.waiter_user,10,'
')||' '||rpad(to_char(v_waiters.inst_id),4,' ')||rpad(to_char(v_waiters.sid),4,'
')|| ' '||lpad(to_char(v_waiters.serial),12,' ')||' ' ||' '||
' ' ||lpad(to_char(v_waiters.ctime),6,' ')||' '||
lpad(to_char(v_waiters.lock_req),13,' ') || ' '||
lpad(to_char(v_waiters.module),15,' ')
);
END LOOP;
END LOOP;
IF bHasAny THEN
i:=i+1;
END IF;
END LOOP;
IF bHasAny THEN
DBMS_OUTPUT.PUT_LINE (chr(9));
DBMS_OUTPUT.PUT_LINE ('To kill first from the list, perform: ');
DBMS_OUTPUT.PUT_LINE (chr(9));
IF bOnTheSameNode THEN
DBMS_OUTPUT.PUT_LINE (chr(9)||'exec
dba_tools.safe_kill('||v_sid||','||v_serial||');');
DBMS_OUTPUT.PUT_LINE (chr(9));
kill_by_hand;
ELSE
IF db_ver like '10%' THEN
s := '''begin execute immediate ''''ALTER SYSTEM KILL SESSION
'''''''''||v_sid||','||v_serial||''''''''' IMMEDIATE''''; end; ''';
dbms_output.put_line(s);
DBMS_OUTPUT.PUT_LINE (chr(9));
s_job_command := 'declare'|| chr(10)||
'v_job binary_integer;'|| chr(10)||
'begin'|| chr(10)||
'DBMS_JOB.submit (job=>v_job'||chr(10)||
',what=>'||s||chr(10)||
',instance=>'||v_instance||chr(10)||
'); '||chr(10)||
'DBMS_OUTPUT.PUT_LINE(to_char(v_job));'||chr(10)||
'commit;'||chr(10)||
'end;'|| chr(10) ||
'/'
;
dbms_output.put_line(s_job_command);
ELSIF db_ver like '11%' THEN
DBMS_OUTPUT.PUT_LINE (chr(9)||'exec
dba_tools.safe_kill('||v_sid||','||v_serial||','||v_instance||');');
DBMS_OUTPUT.PUT_LINE (chr(9));
DBMS_OUTPUT.PUT_LINE (chr(9)||'ALTER SYSTEM DISCONNECT SESSION
'''||v_sid||','||v_serial||',@'||v_instance||''' IMMEDIATE;');
DBMS_OUTPUT.PUT_LINE (chr(9)||'ALTER SYSTEM KILL SESSION
'''||v_sid||','||v_serial||',@'||v_instance||''' IMMEDIATE;');
ELSE
dbms_output.put_line('Try to logon as priveledged user on node
('||v_instance||') and perform:');
kill_by_hand;
END IF;
END IF;
ELSE
dbms_output.put_line('No blocking users or process!');
END IF;
end;
/
declare
v_job binary_integer;
begin
DBMS_JOB.submit (job=>v_job
,what=>'begin execute immediate ''ALTER SYSTEM KILL SESSION ''''153,7087''''
IMMEDIATE''; end; '
,instance=>1
);
DBMS_OUTPUT.PUT_LINE(to_char(v_job));
commit;
end;
/
Elapsed: 00:00:01.64
15:54:15 DAMIRV@test3>
As you can see user SCOTT (instance number 1) is blocking two sessions, JOHN (connected on
instance 3) and MARRY (on instance 2) for 5 and 75 seconds. DBA has connected with sqlplus tool
on instance 3 (look at the sql prompt-DAMIRV@test3).
To use ordinary DISCONNECT SESSION command DBA must be on the same node as blocker, what
sometimes is not easy to produce if RAC is driven with some load balancing system which connect
to node with most free resources. For such a cases, beside classic command, script generate
additional output where DBA kill session with job. To perform that solution copy/paste code that
starts from “declare” .
For the same situation Oracle 11g script will produce output like:
ALTER SYSTEM KILL SESSION '153,7087,@1' IMMEDIATE;
what is enhancement in 11g because session can be killed without submitting a job but only
declaring instance number, regardless on what node you are logged on.
Date : 18.07.2009.
Author : Damir Vadas
Remarks : Tested on 10g only (should work on 11g as well and lower versions)
To be able to send mail functionality "utl_mail" must be installed and
granted to user
Put in Oracle job with window of 5 minutes (default)
AS
cursor c_blockers IS
SELECT DISTINCT
username blocker_user,
gvb.sid,
gvs.serial# serial,
gvb.inst_id,
gvb.ctime ,
module,
decode(gvb.type, 'MR', 'Media_recovery',
'RT', 'Redo_thread',
'UN', 'User_name',
'TX', 'Transaction',
'TM', 'Dml',
'UL', 'PLSQL User_lock',
'DX', 'Distrted_Transaxion',
'CF', 'Control_file',
'IS', 'Instance_state',
'FS', 'File_set',
'IR', 'Instance_recovery',
'ST', 'Diskspace Transaction',
'IV', 'Libcache_invalidation',
'LS', 'LogStaartORswitch',
'RW', 'Row_wait',
'SQ', 'Sequence_no',
'TE', 'Extend_table',
'TT', 'Temp_table',
'Nothing-'
) lock_type,
action
FROM gv$lock gvb, gv$lock gvw, gv$session gvs
WHERE (gvb.id1, gvb.id2) in (
SELECT id1, id2 FROM gv$lock WHERE request=0
INTERSECT
SELECT id1, id2 FROM gv$lock WHERE lmode=0
)
AND gvb.id1=gvw.id1
AND gvb.id2=gvw.id2
AND gvb.request=0
AND gvw.lmode=0
AND gvb.sid=gvs.sid
AND gvb.inst_id=gvs.inst_id
ORDER BY CTIME desc
;
CURSOR c_w IS
SELECT gvw.sid waiter_sid,
gvw.inst_id waiter_inst_id
FROM gv$lock gvb, gv$lock gvw, gv$session gvs
WHERE (gvb.id1, gvb.id2) in (
SELECT id1, id2 FROM gv$lock WHERE request=0
INTERSECT
SELECT id1, id2 FROM gv$lock WHERE lmode=0
)
AND gvb.id1=gvw.id1
AND gvb.id2=gvw.id2
AND gvb.request=0
AND gvw.lmode=0
AND gvb.sid=gvs.sid
AND gvb.inst_id=gvs.inst_id
ORDER BY gvb.CTIME desc
;
bHasAny boolean;
i NUMBER := 0;
v_sid NUMBER := 0;
v_serial NUMBER := 0;
v_instance BINARY_INTEGER := 0;
db_ver VARCHAR2(128);
db_ver2 VARCHAR2(128);
s_job_command VARCHAR2 (4000);
s_mail_text VARCHAR2 (4000);
s_subject VARCHAR2 (256);
s_smtp_out_server VARCHAR2 (256);
s_host_name v$instance.host_name%TYPE;
s_db_name v$database.name%TYPE;
s_instance_name v$instance.instance_name%TYPE;
s VARCHAR2(1024);
Then you have to create Oracle job, which will repeat checking periodically (in our case 5 minutes):
DECLARE
X NUMBER;
BEGIN
SYS.DBMS_JOB.SUBMIT (
job => X
,what => 'check_blocking_session;'
,next_date => to_date('13/11/2009 13:09:02','dd/mm/yyyy hh24:mi:ss')
,interval => 'SYSDATE+5/1440'
,no_parse => FALSE
);
SYS.DBMS_OUTPUT.PUT_LINE('Job Number is: ' || to_char(x));
COMMIT;
END;
/