本章参考文档:
官方文档《Database Concepts》
-> Data Concurrency and Consistency
http://docs.oracle.com/cd/E11882_01/server.112/e40540/consist.htm - CNCPT020
col WAIT_EVENT_TEXT for a30
col WAITER_INSTID_SID_SERIAL# for a25
col blocker_instid_sid_serial# for a26
set linesize 120
set pagesize 999
SELECT inst_id || '_' || sid || '_' || SESS_SERIAL# waiter_instid_sid_serial#,
WAIT_EVENT_TEXT,
BLOCKER_INSTANCE_ID
|| '_'
|| BLOCKER_SID
|| '_'
|| BLOCKER_SESS_SERIAL#
blocker_instid_sid_serial#
FROM gv$session_blockers;
col waiting_session for a20
col lock_type for a15
col mode_requested for a10
col mode_held for a10
col lock_id1 for a10
col lock_id2 for a10
set linesize 120
set pagesize 999
with dba_locks_cust as
(SELECT inst_id||'_'||sid session_id,
DECODE (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',
'TS', 'Temp Segment',
'IV', 'Library Cache Invalidation',
'LS', 'Log Start or Switch',
'RW', 'Row Wait',
'SQ', 'Sequence Number',
'TE', 'Extend Table',
'TT', 'Temp Table',
TYPE)
lock_type,
DECODE (lmode,
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 (lmode))
mode_held,
DECODE (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 (request))
mode_requested,
TO_CHAR (id1) lock_id1,
TO_CHAR (id2) lock_id2,
ctime last_convert,
DECODE (block,
0, 'Not Blocking', /* Not blocking any other processes */
1, 'Blocking', /* This lock blocks other processes */
2, 'Global', /* This lock is global, so we can't tell */
TO_CHAR (block))
blocking_others
FROM gv$lock
),
lock_temp as
(select * from dba_locks_cust),
lock_holder as
(
select w.session_id waiting_session,
h.session_id holding_session,
w.lock_type,
h.mode_held,
w.mode_requested,
w.lock_id1,
w.lock_id2
from lock_temp w, lock_temp h
where h.blocking_others in ('Blocking','Global')
and h.mode_held != 'None'
and h.mode_held != 'Null'
and w.mode_requested != 'None'
and w.lock_type = h.lock_type
and w.lock_id1 = h.lock_id1
and w.lock_id2 = h.lock_id2
),
lock_holders as
(select waiting_session,holding_session,lock_type,mode_held,
mode_requested,lock_id1,lock_id2
from lock_holder
union all
select holding_session, null, 'None', null, null, null, null
from lock_holder
minus
select waiting_session, null, 'None', null, null, null, null
from lock_holder
)
select lpad(' ',3*(level-1)) || waiting_session waiting_session,
lock_type,
mode_requested,
mode_held,
lock_id1,
lock_id2
from lock_holders
connect by prior waiting_session = holding_session
start with holding_session is null;
set serveroutput on size unlimited
set feedback off
DECLARE
v_num_sessions INTEGER := 0;
CURSOR cv IS
SELECT
dba_objects.object_name,
locks_t.row#,
locks_t.blocked_secs,
locks_t.blocker_text,
locks_t.blocked_text,
locks_t.blocked_sql_text
FROM (SELECT /*+ NO_MERGE */
blocking_lock_session.username||'@'||blocking_lock_session.machine||'(INST_ID='||blocking_lock_session.inst_id||',SID='||blocking_lock_session.sid||') ['||
blocking_lock_session.program||'/PID='||blocking_lock_session.process||']' as blocker_text,
blocked_lock_session.username||'@'||blocked_lock_session.machine|| '(INST_ID='||blocked_lock_session.inst_id||',SID='||blocked_lock_session.sid||') ['||
blocked_lock_session.program||'/PID='||blocked_lock_session.process||']' as blocked_text,
blocked_lock_session.row_wait_obj#,
blocked_lock_session.row_wait_file#,
blocked_lock_session.row_wait_block#,
blocked_lock_session.row_wait_row#,
DBMS_ROWID.ROWID_CREATE (1,
blocked_lock_session.row_wait_obj#,
blocked_lock_session.row_wait_file#,
blocked_lock_session.row_wait_block#,
blocked_lock_session.row_wait_row#) row#,
blocked_lock_session.seconds_in_wait blocked_secs,
blocked_sql.sql_text blocked_sql_text
FROM gv$lock blocking_lock,
gv$session blocking_lock_session,
gv$lock blocked_lock,
gv$session blocked_lock_session,
gv$sql blocked_sql
WHERE blocking_lock.inst_id=blocking_lock_session.inst_id
and blocked_lock.inst_id=blocked_lock_session.inst_id
and blocked_lock_session.inst_id=blocked_sql.inst_id
and blocking_lock.block = 1
AND blocking_lock.id1 = blocked_lock.id1
AND blocking_lock.id2 = blocked_lock.id2
AND blocked_lock.request > 0
AND blocking_lock.sid = blocking_lock_session.sid
AND blocked_lock.sid = blocked_lock_session.sid
AND blocked_lock_session.sql_id = blocked_sql.sql_id
AND blocked_lock_session.sql_child_number = blocked_sql.child_number
) locks_t,
dba_objects
WHERE locks_t.row_wait_obj# = dba_objects.object_id
AND locks_t.blocked_secs > 10
ORDER BY locks_t.blocked_secs;
BEGIN
FOR cv_rec IN cv LOOP
dbms_output.put_line(
'========= $Revision: 1.4 $ ($Date: 2013/09/16 13:15:22 $) ===========');
v_num_sessions := v_num_sessions + 1;
dbms_output.put_line('Locked object : '||
cv_rec.object_name);
dbms_output.put_line('Locked row# : '||
cv_rec.row#);
dbms_output.put_line('Blocked for : '||
cv_rec.blocked_secs||' seconds');
dbms_output.put_line('Blocker info. : '||
cv_rec.blocker_text);
dbms_output.put_line('Blocked info. : '||
cv_rec.blocked_text);
dbms_output.put_line('Blocked SQL : '||
cv_rec.blocked_sql_text);
END LOOP;
dbms_output.new_line;
dbms_output.put_line('Found '||TO_CHAR(v_num_sessions)||
' blocked session(s).');
END;
/
col waiting_session for a20
col lock_type for a15
col mode_requested for a10
col mode_held for a10
col lock_id1 for a10
col lock_id2 for a10
set linesize 120
set pagesize 999
with lock_temp as
(select * from dba_locks),
lock_holder as
(
select w.session_id waiting_session,
h.session_id holding_session,
w.lock_type,
h.mode_held,
w.mode_requested,
w.lock_id1,
w.lock_id2
from lock_temp w, lock_temp h
where h.blocking_others = 'Blocking'
and h.mode_held != 'None'
and h.mode_held != 'Null'
and w.mode_requested != 'None'
and w.lock_type = h.lock_type
and w.lock_id1 = h.lock_id1
and w.lock_id2 = h.lock_id2
),
lock_holders as
(select waiting_session,holding_session,lock_type,mode_held,
mode_requested,lock_id1,lock_id2
from lock_holder
union all
select holding_session, null, 'None', null, null, null, null
from lock_holder
minus
select waiting_session, null, 'None', null, null, null, null
from lock_holder
)
select lpad(' ',3*(level-1)) || waiting_session waiting_session,
lock_type,
mode_requested,
mode_held,
lock_id1,
lock_id2
from lock_holders
connect by prior waiting_session = holding_session
start with holding_session is null;
set linesize 120
set pagesize 999
select waiting_session,holding_session,lock_type,lock_id1,mode_held from dba_waiters;
drop table lock_holders;
create table LOCK_HOLDERS /* temporary table */
(
waiting_session number,
holding_session number,
lock_type varchar2(26),
mode_held varchar2(14),
mode_requested varchar2(14),
lock_id1 varchar2(22),
lock_id2 varchar2(22)
);
drop table dba_locks_temp;
create table dba_locks_temp as select * from dba_locks;
/* This is essentially a copy of the dba_waiters view but runs faster since
* it caches the result of selecting from dba_locks.
*/
insert into lock_holders
select w.session_id,
h.session_id,
w.lock_type,
h.mode_held,
w.mode_requested,
w.lock_id1,
w.lock_id2
from dba_locks_temp w, dba_locks_temp h
where h.blocking_others = 'Blocking'
and h.mode_held != 'None'
and h.mode_held != 'Null'
and w.mode_requested != 'None'
and w.lock_type = h.lock_type
and w.lock_id1 = h.lock_id1
and w.lock_id2 = h.lock_id2;
commit;
drop table dba_locks_temp;
insert into lock_holders
select holding_session, null, 'None', null, null, null, null
from lock_holders
minus
select waiting_session, null, 'None', null, null, null, null
from lock_holders;
commit;
column waiting_session format a17;
column lock_type format a17;
column lock_id1 format a17;
column lock_id2 format a17;
/* Print out the result in a tree structured fashion */
select lpad(' ',3*(level-1)) || waiting_session waiting_session,
lock_type,
mode_requested,
mode_held,
lock_id1,
lock_id2
from lock_holders
connect by prior waiting_session = holding_session
start with holding_session is null;
drop table lock_holders;
col object_name for a30
set linesize 120
set pagesize 999
SELECT a.inst_id,
a.session_id,
b.object_name,
b.object_type,
a.locked_mode
FROM gv$locked_object a, dba_objects b
WHERE a.object_id = b.object_id AND b.object_name = '
elect /*+ ordered */ w1.sid waiting_session,
h1.sid holding_session,
w.kgllktype lock_or_pin,
w.kgllkhdl address,
decode(h.kgllkmod, 0, 'None', 1, 'Null', 2, 'Share', 3, 'Exclusive',
'Unknown') mode_held,
decode(w.kgllkreq, 0, 'None', 1, 'Null', 2, 'Share', 3, 'Exclusive',
'Unknown') mode_requested
from dba_kgllock w, dba_kgllock h, v$session w1, v$session h1
where
(((h.kgllkmod != 0) and (h.kgllkmod != 1)
and ((h.kgllkreq = 0) or (h.kgllkreq = 1)))
and
(((w.kgllkmod = 0) or (w.kgllkmod= 1))
and ((w.kgllkreq != 0) and (w.kgllkreq != 1))))
and w.kgllktype = h.kgllktype
and w.kgllkhdl = h.kgllkhdl
and w.kgllkuse = w1.saddr
and h.kgllkuse = h1.saddr
/
waiting_session 是被阻塞的会话,holding_session是阻塞者,address是被阻塞对象的地址,可通过如下语句查看对象名称
select to_name from v$object_dependency where to_address = '';
通过session id,也可以查看该会话所使用的library对象
select distinct kglnaobj from x$kgllk where
kgllkuse in (select saddr from v$session where sid =
参考文档How to Analyze Library Cache Timeout with Associated: ORA-04021 'timeout occurred while waiting to lock object %s%s%s%s%s.' Errors (文档ID 1486712.1)
col object for a30
col owner for a20
col type for a20
set linesize 120
set pagesize 999
select * from gv$access where owner='
COL program FOR a30
COL event FOR a30
COL waiting_obj FOR a25
SET LINESIZE 130
SET PAGESIZE 999
SELECT b.kglnaown || '.' || b.kglnaobj waiting_obj,
c.sid,
c.username,
c.program,
c.event,
c.sql_id
FROM dba_kgllock a, x$kglob b, v$session c
WHERE ( (a.kgllkmod = 0)
OR (a.kgllkmod = 1)
AND ( (a.kgllkreq != 0) AND (a.kgllkreq != 1)))
AND a.kgllkhdl = b.kglhdadr
AND a.kgllkuse = c.saddr;
COL username FOR a15
COL program FOR a30
COL event FOR a30
COL waiting_obj FOR a25
SET LINESIZE 130
SET PAGESIZE 999
SELECT b.kglnaown || '.' || b.kglnaobj waiting_obj,
c.sid,
c.username,
c.program,
c.event,
c.sql_id
FROM x$kglpn a, x$kglob b, v$session c
WHERE ( (a.kglpnmod != 0)
AND (a.kglpnmod != 1)
AND ( (a.kglpnreq = 0) OR (a.kglpnreq = 1)))
AND a.kglpnhdl = b.kglhdadr
AND a.kglpnuse = c.saddr
AND b.kglnaown = 'TEST'
AND b.kglnaobj = 'TESTSL';
col inst_id for 99
col sid for 9999
col serial# for 99999
col spid for 9999999
col username for a10
col program for a30
col event for a30
set linesize 130
SELECT a.inst_id,
a.sid,
a.serial#,
b.spid, --该回话对应操作系统层面的进程号
a.username,
a.program,
a.event,
a.sql_id
FROM gv$session a, gv$process b
WHERE a.inst_id = b.inst_id
AND a.paddr = b.addr
AND a.inst_id =
select spid, program from v$process
where program!= 'PSEUDO'
and addr not in (select paddr from v$session)
and addr not in (select paddr from v$bgprocess)
and addr not in (select paddr from v$shared_server);
对于RAC
select INST_ID, spid, program,'kill -9 '|| spid kill9
from gv$process a
where program != 'PSEUDO'
and (INST_ID, addr) not in (select INST_ID, paddr from gv$session)
and (INST_ID, addr) not in (select INST_ID, paddr from gv$bgprocess)
and (INST_ID, addr) not in (select INST_ID, paddr from gv$shared_server)
and a.PNAME is null;
set line 9999
col sessionid format a20
col sessionid_killed format a20
col kill_session format a60
SELECT a.INST_ID,
a.SID || ',' || a.SERIAL# || ',' ||
(select spid
from gv$process b
where b.INST_ID = a.INST_ID
and A.creator_addr = b.ADDR --and decode(a.status,'KILLED',A.creator_addr,A.PADDR) = b.ADDR
) sessionid,
a.PADDR,
a.STATUS,
a.PROGRAM,
'alter system disconnect session ''' || sid || ',' || serial# || ''' immediate;' kill_session
FROM gv$session a
WHERE a.USERNAME = 'SYS'
and a.STATUS = 'KILLED';
SELECT a.SID || ',' || a.SERIAL# || ',' ||
(select spid
from gv$process b
where b.INST_ID = a.INST_ID
and A.pid = b.pid) sessionid,
'alter system kill session ''' || sid || ',' || serial# || ''';' kill_session
FROM gV$DETACHED_SESSION a;
SELECT s.SID, s.username,s.status,
x.ADDR,x.KSLLAPSC,x.KSLLAPSN,x.KSLLASPO,x.KSLLID1R,x.KSLLRTYP,
decode(bitand(x.ksuprflg,2),0,null,1)
FROM x$ksupr x,v$session s
WHERE s.paddr(+)=x.addr
and bitand(ksspaflg,1)!=0
;
delete语句为:
delete from hldrs.kc21 where aaz217=97
kc21表aaz217字段是主键,存在主键索引,字段类型也是number,但经测试,该语句执行需要3分钟。
查看该语句执行计划,确实走的是index unique scan,理论上应该很快结束,使用10046事件跟踪语句执行过程,发现该语句后台不只执行delete的操作,还有一个针对kc24表的全表查询
原因很清楚了,在对kc21表进行delete时,相当于减少了主键字段数据,而由于kc24需要参考该主键,所以要对外键字段进行扫描,检查是否要进行维护,而kc24的外键字段没有索引存在,故只能走全表扫描,kc24表约9gb大小,扫描一次大约要3分钟。
根据以上分析,建议研发在kc24的外键字段上创建索引。经验证,创建索引后删除速度正常。