事务的锁定和阻塞机制

1,oracle锁的分类与产生
Oracle是一个多用户使用的共享资源。加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对象进行操作前,先向系统发出请求,对其加锁。加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前,其他的事务不能对数据对象进行更行操作。

在数据库中有两种基本类型的锁:排他锁(exclusive locks即X锁)和共享锁(share locks即S锁)。

1.1 oracle的锁类型
根据保护的对象不同,oracle数据库锁可以分为以下几个大类:DML锁(data Locks数据锁),用于保护数据的完整性; DDL锁(dictionary locks,字典锁),用于保护数据库对象的结构,如表、索引等的结构定义;内部锁和闩锁(internal locks and latches),保护数据库的内部结构,比如library cache,shared pool等。

DML锁主要包括TM锁和TX锁,其中TM锁称为表级别锁,TX锁称为事务锁或者行级别锁。

A table-level lock(TM)is set for any dml transaction that modifies a table: insert, update, delete, select for update or lock table , the TM prevents DDL operations that would conflict with the transaction.

就是说TM是用来防止和事务冲突的DDL操作,比如在insert时防止表被drop。

The row-level lock(TX) is automatically acquired for each row modified by insert, update, delete or select for update . the row-level lock ensures that no other user can modify the same row at the same time . therefore , there is no risk that a user can modify a row that is being modified and not yet committed by another user.

TX锁是为了保护数据的一致性,就是说不能在同一时间修改相同的行。

当oracle执行DML语句时,系统自动在所要操作的表上申请TM类型的锁,当TM锁获得后,系统再申请TX类型的锁。这样在事务加锁前检查TX锁相容性时就不用再逐行检查锁标志,而只需要检查TM锁模式的兼容性即可,大大提高了系统的效率。

在数据行上只有TX锁,oracle执行select语句时不对行对象进行任何锁定,当oracle数据库发生TX锁等待时,如果不及时处理会引起oracle数据库挂起,或者导致锁的发生,产生ora-600错误。这些现象都会对实际应用产生极大的危害,如长时间未响应,大量事务失败等。

1.2 悲观封锁和乐观封锁
悲观封锁

锁在用户修改之前就发挥作用(select * from table1 for update)。用户发出上述语句后,oracle将会对返回的结果集建立行级别TX锁,以防止其他用户对相同记录的修改,同时会在表上建立一个编号为3的TM锁。

乐观封锁

乐观的封锁认为数据在select出来到update进行到提交这段时间数据不会被更改,这里面有一种潜在的威胁就是由于被选出来的结果集并没有被锁定,所以可能被其他用户修改了。比如我们系统中经常出现的:

Declare

  C1 integer;

Begin

Select count(1) into C1 from table1 where f1 = :f1;

If C1 = 1 then

  Update …

Elsif

  Insert

End if;

    End;

1.3 阻塞
定义:

当一个会话保持另一个会话正在请求的资源上的锁定时,就会发生阻塞。被阻塞的会话将会一直挂起,知道持有锁的会话放弃锁定的资源为止。四个常见的dml语句会产生阻塞。

Insert

Update

Delete

Select 。。。 for update

Insert 发生阻塞的唯一情况就是用户拥有一个建有主键(唯一约束)的表。当两个会话同时试图向表中插入相同的数据时,其中的一个会话将被阻塞,直到另外一个会话提交或回滚。

Update&delete当执行操作的数据行已经被另外的会话锁定时,将会发生阻塞,直到另一个会话提交或回滚。

当用户发出select for update语句准备对返回的结果集进行修改时,如果结果集已经被另外的会话锁定,则会发生阻塞。需要等另外一个会话结束才可继续进行。可以通过发出select for update nowait的语句来避免发生阻塞。这时如果资源被锁定,则会返回错误。

1.4 TM锁的类型
锁模式
 锁描述
 解释
 SQL操作
 
0
 None
 
 
 
1
 Null
 空
 Select
 
2
 RS(ROW-S)
 行级别共享锁,其他对象只能查询这些数据
 Select for update

Lock for update

Lock row share
 
3
 RX(ROW-X)
 行级别排他锁,提交前不允许DML操作
 Insert ,update , delete, lock row share
 
4
 S(SHARE)
 共享锁
 Create index

Lock share
 
5
 SRX(S/ROW-X)
 共享行级别排他锁
 Lock share row exclusive
 
6
 X(EXCLUSIVE)
 排他锁
 Alter table、drop table、drop index、truncate table、lock exclusive
 


TM是对象锁,表示可能在这个对象上做什么操作,还没有结束,所以不允许DDL。即使update where 1=0,因为锁定发生在真实修改发生之前,不知道会修改多少记录,所以TM先产生。TM共具有5种模式

行级别排他锁(RX row exclusive)

当我们进行DML时会自动在被更新的表上加RX锁,或者也可以通过lock table t1 in row exclusive mode;命令显式添加RX锁。在该锁定模式下,允许其他的事务通过DML语句修改相同表里的其他数据行,或者通过lock命令对相同表添加RX锁定,但不允许其他事务对相同的表添加排他锁(X锁)。

行级别共享锁(RS row shared)

通常是通过select 。。。 for update语句添加的,同时该方法也是我们用来手工锁定某些记录的主要方法。比如,当我们在查询某些记录的过程中,不希望其他用户对查询的记录进行更新操作,则可以发出这样的语句。当数据使用完毕时,直接rollback命令将锁定解除。当表上添加了RS锁定以后,不允许其他事务对相同的表添加排他锁,但是允许其他的事务通过DML语句或lock命令锁定相同表里的其他数据行。

共享锁(S  share)

通过lock table in share mode 命令添加S锁,在锁定模式下,不允许任何用户更新表,但是允许其他用户发出select 。。。 from table for update 命令对表添加RS锁。(这里有点问题,10g的测试结果,select for update给出的是rx锁,并且在s锁已经添加的情况下无法添加rx锁)

排他锁(X exclusive)

通过lock table in exclusive mode命令添加X锁。在该锁定模式下,其他用户不能对表进行任何的DML和DDL操作,该表上只能查询。

共享行级别排他锁(SRX share row exclusive)

通过lock table in share row exclusive mode命令添加SRX锁。该锁定模式比行级别排他锁和共享锁的级别都要高,这时不能对相同的表进行DML操作,也不能添加共享锁。

五种模式的TM锁的兼容关系如下表所示((√表示互相兼容的请求;×表示互相不兼容的请求;N/A表示没有锁定请求)。

-
 S
 X
 RS
 RX
 SRX
 N/A
 
S
 √
 ×
 √
 ×
 ×
 √
 
X
 ×
 ×
 ×
 ×
 ×
 √
 
RS
 √
 ×
 √
 √
 √
 √
 
RX
 ×
 ×
 √
 √
 ×
 √
 
SRX
 ×
 ×
 √
 ×
 ×
 √
 
N/A
 √
 √
 √
 √
 √
 √
 

 

从前面的描述中可以看到,我们不仅可以通过发出DML语句的方式,由Oracle自动在表级别上添加TM锁。我们还可以通过发出lock table命令主动地在表级别上添加TM锁,并在该命令中可以指定不同的锁定模式,其命令格式如下所示:

lock table in [row share][row exclusive][share][share row exclusive][exclusive] mode;

对Oracle数据库中的各SQL语句所产生的表级锁的情况进行汇总,如下表所示:

SQL语句
 表锁定模
 允许的表锁定模式
 
Select * from ……
 RS
 RS、RX、S、SRX、X
 
Insert into ……
 RX
 RS、RX
 
Update ……
 RX
 RS、RX
 
Delete from ……
 RX
 RS、RX
 
Select * from for update
 RS
 RS、RX、S、SRX
 
lock table in row share mode
 RS
 RS、RX、S、SRX
 
lock table in row exclusive mode
 RX
 RS、RX
 
lock table in share mode
 S
 RS、S
 
lock table in share row exclusive mode
 SRX
 RS
 
lock table in exclusive mode
 X
 RS
 

对于通过lock table命令主动添加的锁定来说,如果要释放它们,只需要发出rollback命令即可。

 

1.5 TX锁的类型
假设某个用户(假设为A)发出如下的语句更新一条记录:

 SQL> update employees set last_name='HanSijie' where employee_id=100;
 

 Oracle在对该SQL进行解析以后,找到employee_id为100的记录所在的数据块(假设为58号数据块),并找一个可用的undo数据块,将last_name列上被更新前的旧值放入该undo数据块,然后在数据块头部分配一个ITL槽,在该ITL槽里存放当前的事务ID号、SCN号、所使用的undo数据块的地址,以及当前还未提交的标记等信息。接下来,在58号数据块中,找到被更新的数据行,在其头部设置一个锁定标记,并在头部记录当前事务所使用的ITL槽的槽号。做完这些工作以后,将控制权(也就是光标)返回给用户。该锁定标记说明当前用户在被修改的数据行上已经添加了X锁。

如果这时,另一个用户(假设为N)也对employee_id为100的记录进行修改,则其过程和上面描述的一样,只不过B在对数据行的头部设置锁定标记时,发现该数据行头部已经有一个锁定标记了,说明该记录已经被添加了X锁,于是用户进程N必须等待,等待该X锁被释放。

可以看到,Oracle数据库是在物理层面上实现对数据行的锁定问题。而且锁定一条记录,并不影响其他用户对该记录的读取。比如,如果当前有一个用户(假设为C)发出SQL语句,检索employee_id为100的记录信息,这时服务器进程发现被检索的记录有锁定标记,说明当前该记录已经被其他用户修改了,但是还没提交。于是根据数据行头部记录的ITL槽的槽号,在数据块头部找到该ITL槽,并根据其中记录的undo数据块的地址,找到该undo数据块,将其中所保存的改变前的旧值取出,并据此构建CR(Consistent Read一致性读)块,该CR块中的数据就是被更新的数据块(也就是58号数据块)在更新前的内容。于是根据该CR块的内容,将用户所需要的信息返回给C。

对于Oracle数据库来说,行级锁只有X锁定模式,没有S锁定模式。Oracle的锁定总是尽可能地在最低级别上完成。比如更新数据行时,仅仅是锁定被更新的数据行,并不会锁定同一个数据块中的其他数据行,也不会阻塞其他用户查询被更新的数据行。

2,锁相关的数据字典
2.1 关于v$lock
This view lists the locks currently held by the Oracle Database and outstanding requests for a lock or latch.

Column
 Datatype
 Description
 
ADDR
 RAW(4 | 8)
 Address of lock state object
 
KADDR
 RAW(4 | 8)
 Address of lock
 
SID
 NUMBER
 Identifier for session holding or acquiring the lock
 
TYPE
 VARCHAR2(2)
 Type of user or system lock

The locks on the user types are obtained by user applications. Any process that is blocking others is likely to be holding one of these locks. The user type locks are:

TM - DML enqueue

TX - Transaction enqueue

UL - User supplied

The locks on the system types are held for extremely short periods of time. The system type locks are listed in Table 6-1.

我们主要关注TM和TX两种锁类型。UL锁为用户自定义的锁,一般很少会定义,基本不用关注。其他均为系统锁,会很快自动释放,不用关注。
 
ID1
 NUMBER
 Lock identifier #1 (depends on type)
 
ID2
 NUMBER
 Lock identifier #2 (depends on type)

当lock type 为TM时,id1为DML-locked object的object_id。当LOCK TYPE为TX时,id1为usn+slot,而id2为seq。当lock type为其他时,不用关注
 
LMODE
 NUMBER
 Lock mode in which the session holds the lock:

0 - none
1 - null (NULL)
2 - row-S (SS)
3 - row-X (SX)
4 - share (S)
5 - S/Row-X (SSX)
6 - exclusive (X)
大于0时表示当前会话以某种方式占有该锁,等于0时表示当前会话正在等待该锁资源,即表示该会话被阻塞。
 
REQUEST
 NUMBER
 Lock mode in which the process requests the lock:

0 - none
1 - null (NULL)
2 - row-S (SS)
3 - row-X (SX)
4 - share (S)
5 - S/Row-X (SSX)
6 - exclusive (X)
大于0时,这里给出的是阻塞当前会话的其他会话锁定资源的模式。
 
CTIME
 NUMBER
 Time since current mode was granted
 
BLOCK
 NUMBER
 A value of either 0 or 1, depending on whether or not the lock in question is the blocker.

0:not blocking any other processes

1:this lock blocks other processes
 


 

Table 6-1 Values for the TYPE Column: System Types

System Type
 Description
 System Type
 Description
 
BL
 Buffer hash table instance
 NA..NZ
 Library cache pin instance (A..Z = namespace)
 
CF
 Control file schema global enqueue
 PF
 Password File
 
CI
 Cross-instance function invocation instance
 PI, PS
 Parallel operation
 
CU
 Cursor bind
 PR
 Process startup
 
DF
 datafile instance
 QA..QZ
 Row cache instance (A..Z = cache)
 
DL
 Direct loader parallel index create
 RT
 Redo thread global enqueue
 
DM
 Mount/startup db primary/secondary instance
 SC
 System change number instance
 
DR
 Distributed recovery process
 SM
 SMON
 
DX
 Distributed transaction entry
 SN
 Sequence number instance
 
FS
 File set
 SQ
 Sequence number enqueue
 
HW
 Space management operations on a specific segment
 SS
 Sort segment
 
IN
 Instance number
 ST
 Space transaction enqueue
 
IR
 Instance recovery serialization global enqueue
 SV
 Sequence number value
 
IS
 Instance state
 TA
 Generic enqueue
 
IV
 Library cache invalidation instance
 TS
 Temporary segment enqueue (ID2=0)
 
JQ
 Job queue
 TS
 New block allocation enqueue (ID2=1)
 
KK
 Thread kick
 TT
 Temporary table enqueue
 
LA .. LP
 Library cache lock instance lock (A..P = namespace)
 UN
 User name
 
MM
 Mount definition global enqueue
 US
 Undo segment DDL
 
MR
 Media recovery
 WL
 Being-written redo log instance
 


 

 

2.2 其他相关视图说明
视图名
 描述
 主要字段说明
 
v$session
 查询会话的信息和锁的信息。
 sid,serial#:表示会话信息。

program:表示会话的应用程序信息。

row_wait_obj#:表示等待的对象,和dba_objects中的object_id相对应。

lockwait :该会话等待的锁的地址,与v$lock的kaddr对应.
 
v$session_wait
 查询等待的会话信息。
 sid:表示持有锁的会话信息。

Seconds_in_wait:表示等待持续的时间信息

Event:表示会话等待的事件,锁等于enqueue
 
 
 
 
 
dba_locks
 对v$lock的格式化视图。
 Session_id:和v$lock中的Sid对应。

Lock_type:和v$lock中的type对应。

Lock_ID1: 和v$lock中的ID1对应。

Mode_held,mode_requested:和v$lock中

的lmode,request相对应。
 
v$locked_object
 只包含DML的锁信息,包括回滚段和会话信息。
 Xidusn,xidslot,xidsqn:表示回滚段信息。和

v$transaction相关联。

Object_id:表示被锁对象标识。

Session_id:表示持有锁的会话信息。

Locked_mode:表示会话等待的锁模式的信

息,和v$lock中的lmode一致。
 


3,锁相关的sql statement
3.1 TM阻塞的检索

select /*+ rule*/
  lpad('--',decode(b.block,1,0,4))||s.USERNAME user_name,
  b.TYPE,o.owner||'.'||o.object_name object_name,
  s.SID,s.SERIAL#,decode(b.REQUEST,0,'blocked','waiting') status 
from dba_objects o,v$session s,v$lock v,v$lock b
where v.ID1 = o.object_id
  and v.SID = b.SID
  and v.SID = s.SID
  and (b.BLOCK = 1 or b.REQUEST > 0)
  and v.TYPE = 'TM'
order by b.ID2,v.ID1,user_name desc;

 

3.2 latch阻塞的检索

select sql_text
from v$sqlarea s
where (s.ADDRESS,s.HASH_VALUE ) in
      (
        select sql_address,sql_hash_value
        from v$session
        where sid in
          (
            select sid
            from v$session a,sys.x$kglpn b
            where a.SADDR = b.kglpnuse
              and b.kglpnmod <> 0
              and b.kglpnhdl in
                  (
                    select p1raw
                    from v$session_wait
                    where sid = &sid
                      and event like 'library%'
                  )
          )
      )

 

3.3. 用于检查系统中锁的简单脚本

select s.username, s.sid, l.type, l.id1, l.id2, l.lmode, l.request, p.spid PID
from v$lock l, v$session s, v$process p
where s.sid = l.sid
and   p.addr = s.paddr
and   s.username is not null
order by id1, s.sid, request;

 

 

 

3.4. 显示数据库锁的信息

set pagesize 60
set linesize 132
select s.username username, a.sid sid, a.owner || '.' || a.object object, s.lockwait,   
       t.sql_text sql
from v$sqltext t, v$session s, v$access a
where t.address = s.sql_address
and   t.hash_value = s.sql_hash_value
and   s.sid = a.sid
and   a.owner != 'SYS'
and   upper(substr(a.object,1,2)) != 'V$';
/

 

 

 

3.5. 产生在数据库中持有的锁的报表

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;

 

 

 

3.6. 产生等待锁的用户的报告

column username format a15
column sid format 9990 heading sid
column type format a4
column lmode format 990 heading 'HELD'
column request format 990 heading 'REQ'
column id1 format 9999990
column id2 format 9999990
break on id1 skip 1 dup
spool tfslckwt.lst
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;
spool off
clear breaks

 

 

 

3.7. 显示持有锁的会话的信息

set linesize 132 pagesize 66
break on Kill on username on terminal
column Kill heading 'Kill String' fromat a13
column res heading 'Resource Type' format 999
column id1 format 9999990
column id2 format 9999990
column lmode heading 'Lock Held' format a20
column request heading 'Lock Requested' format a20
column serial# format 99999
column username format a10 heading "Username"
column terminal heading Term format a6
column tab format a35 heading "Table Name"
column owner format a9
column Address format a18
select nvl(s.username, 'Internal') username,
       nvl(s.terminal, 'None') terminal,
       l.sid || ',' || s.serial# Kill,
       u1.name || '.' || substr(t1.name, 1, 20) tab,
       decode(l.lmode, 1, 'No Lock',
                       2, 'Row Share',
                       3, 'Row Exclusive',
                       4, 'Share',
                       5, 'Share Row Exclusive',
                       6, 'Exclusive', null) lmode,
       decode(l.request, 1, 'No Lock',
                         2, 'Row Share',
                         3, 'Row Exclusive',
                         4, 'Share',
                         5, 'Share Row Exclusive',
                         6, 'Exclusive', null) request
from v$lock l, v$session s, sys.user$ u1, sys.obj$ t1
where l.sid = s.sid
and   t1.obj# = decode(l.id2, 0, l.id1, l.id2)
and   u1.user# = t1.owner#
and   s.type != 'BACKGROUND'
order by 1, 2, 5;

 

 

 

3.8. 用于鉴别系统中闩性能的脚本

column name heading "Name" format a20
column pid heading "HSid" format a3
column gets heading "Gets" format 999999990
column misses heading "Miss" format 99990
column im_gets heading "ImG" format 99999990
column im_misses heading "ImM" format 999990
column sleeps heading "Sleeps" format 99990
select n.name name, h.pid pid, l.gets gets, l.misses misses,
       l.immediate_gets im_gets, l.immediate_misses im_misses, l.sleeps sleeps
from v$latchname n, v$latchholder h, v$latch l
where l.latch# = n.latch#
and   l.addr = h.laddr(+);

 

 

 

3.9. 使用v$session wait视图来鉴别闩竞争

select event, p1text, p1, p2text, p2, seq#, wait_time, state
from v$session_wait
where sid = '&&1'
and event = 'latch free';

 


 

 

3.10. 列举用于闩竞争的信息

ttitle center 'Latch Contention Report' skip 3
col name form a25
col gets form 999,999,999
col misses form 999.99
col spins form 999.99
col igets form 999,999,999
col imisses form 999.99
select name, gets,
       misses * 100 / decode(gets, 0, 1, gets) misses,
       spin_gets * 100 / decode(misses, 0, 1, misses) spins,
       immediate_gets igets,
       immediate_misses * 100 / decode(immediate_gets, 0, 1, immediate_gets) imisses
from v$latch
order by gets + immediate_gets;
/

 

 

 

3.11. 检索闩睡眠率

col name form a18 trunc
col gets form 999,999,990
col miss form 90.9
col cspins form a6 heading 'spin | sl06'
col csleep1 form a5 heading 'sl01 | sl07'
col csleep2 form a5 heading 'sl02 | sl08'
col csleep3 form a5 heading 'sl03 | sl09'
col csleep4 form a5 heading 'sl04 | sl10'
col csleep5 form a5 heading 'sl05 | sl11'
col Interval form a12
set recsep off
select a.name, a.gets gets,
       a.misses * 100 / decode(a.gets, 0, 1, a.gets) miss,
       to_char(a.spin_gets * 100 / decode(a.misses, 0, 1, a.misses), '990.9') ||
       to_char(a.sleep6 * 100 / decode(a.misses, 0, 1, a.misses), '90.9') cspins,
       to_char(a.sleep1 * 100 / decode(a.misses, 0, 1, a.misses), '90.9') ||
       to_char(a.sleep7 * 100 / decode(a.misses, 0, 1, a.misses), '90.9') csleep1,
       to_char(a.sleep2 * 100 / decode(a.misses, 0, 1, a.misses), '90.9') ||
       to_char(a.sleep8 * 100 / decode(a.misses, 0, 1, a.misses), '90.9') csleep2,
       to_char(a.sleep3 * 100 / decode(a.misses, 0, 1, a.misses), '90.9') ||
       to_char(a.sleep9 * 100 / decode(a.misses, 0, 1, a.misses), '90.9') csleep3,
       to_char(a.sleep4 * 100 / decode(a.misses, 0, 1, a.misses), '90.9') ||
       to_char(a.sleep10 * 100 / decode(a.misses, 0, 1, a.misses), '90.9') csleep4,
       to_char(a.sleep5 * 100 / decode(a.misses, 0, 1, a.misses), '90.9') ||
       to_char(a.sleep11 * 100 / decode(a.misses, 0, 1, a.misses), '90.9') csleep5
from v$latch a
where a.misses <> 0
order by 2 desc;
/

 

 

 

3.12 oracle TX锁的等待序列

2008-07-16 15:49今天测试GPS在线实时交通系统时,发现主计算节点在更新一张表时一直过不去,费了好一番周折才找到罪魁祸首。下面这段脚本是功臣。
执行这段脚本,能知道哪个数据库用户、哪台机器锁住了该表,哪个用户哪台机器在等待该资源。

SELECT   /*+ choose */
         bs.username "Blocking User", bs.username "DB User",
         ws.username "Waiting User", bs.sid "SID", ws.sid "WSID",
         bs.serial# "Serial#", bs.sql_address "address",
         bs.sql_hash_value "Sql hash", bs.program "Blocking App",
         ws.program "Waiting App", bs.machine "Blocking Machine",
         ws.machine "Waiting Machine", bs.osuser "Blocking OS User",
         ws.osuser "Waiting OS User", bs.serial# "Serial#",
         ws.serial# "WSerial#",
         DECODE (
            wk.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',
            wk.TYPE
         ) lock_type,
         DECODE (
            hk.lmode,
            0, 'None',
            1, 'NULL',
            2, 'ROW-S (SS)',
            3, 'ROW-X (SX)',
            4, 'SHARE',
            5, 'S/ROW-X (SSX)',
            6, 'EXCLUSIVE',
            TO_CHAR (hk.lmode)
         ) mode_held,
         DECODE (
            wk.request,
            0, 'None',
            1, 'NULL',
            2, 'ROW-S (SS)',
            3, 'ROW-X (SX)',
            4, 'SHARE',
            5, 'S/ROW-X (SSX)',
            6, 'EXCLUSIVE',
            TO_CHAR (wk.request)
         ) mode_requested,
         TO_CHAR (hk.id1) lock_id1, TO_CHAR (hk.id2) lock_id2,
         DECODE (
            hk.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 (hk.BLOCK)
         )
               blocking_others
    FROM v$lock hk, v$session bs, v$lock wk, v$session ws
   WHERE hk.BLOCK = 1
     AND hk.lmode != 0
     AND hk.lmode != 1
     AND wk.request != 0
     AND wk.TYPE(+) = hk.TYPE
     AND wk.id1(+) = hk.id1
     AND wk.id2(+) = hk.id2
     AND hk.sid = bs.sid(+)
     AND wk.sid = ws.sid(+)
     AND (bs.username IS NOT NULL)
     AND (bs.username <> 'SYSTEM')
     AND (bs.username <> 'SYS')
ORDER BY 1

 

 

你可能感兴趣的:(oracle,数据库,session,user,table,null)