查锁的方法

查锁的方法:

有用的SQL... PAGEREF _Toc117741710 h 1 08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003100310037003700340031003700310030000000

1:检查系统中锁的简单脚本:... PAGEREF _Toc117741711 h 1 08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003100310037003700340031003700310031000000

2:获取数据库锁的信息(用户IDOBJECTSQL... PAGEREF _Toc117741712 h 1 08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003100310037003700340031003700310032000000

3:产生等待锁的用户报告... PAGEREF _Toc117741713 h 2 08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003100310037003700340031003700310033000000

4:显示持有锁的信息:... PAGEREF _Toc117741714 h 2 08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003100310037003700340031003700310034000000

SQL脚本... PAGEREF _Toc117741715 h 3 08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003100310037003700340031003700310035000000

1. 诊断系统中的锁... PAGEREF _Toc117741716 h 3 08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003100310037003700340031003700310036000000

2. 解除锁... PAGEREF _Toc117741717 h 4 08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003100310037003700340031003700310037000000

一个加速查询锁表和等待锁的方法... PAGEREF _Toc117741718 h 5 08D0C9EA79F9BACE118C8200AA004BA90B02000000080000000E0000005F0054006F0063003100310037003700340031003700310038000000

有用的SQL

1:检查系统中锁的简单脚本:

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.sidrequest;

获取用户SIDPID,锁的种类,锁的类型等信息

2:获取数据库锁的信息(用户IDOBJECTSQL

REM *****************************************************************

REM TITLE : Generic Script which displays SQL Text REM SID
and Object name of the locks currently REM being held in the database.
REM MODULE : lock_held.sql
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
12)) != 'V$' ;
REM REM End of "Lock Monitoring Script" REM

3:产生等待锁的用户报告

SELECT sn.usernamem.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;

4:显示持有锁的信息:

select nvl(S.USERNAME'Internal') username nvl(S.TERMINAL'None') terminal L.SID||''||S.SERIAL# Kill U1.NAME||'.'||substr(T1.NAME120) 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
0L.ID1L.ID2) and U1.USER# = T1.OWNER# and S.TYPE != 'BACKGROUND'
order by 1
25

SQL脚本

1. 诊断系统中的锁

为了找出系统中那些用户锁住资源以及那些用户在等待相应的资源,可使用以下语句(其中的/*+ NO_MERGE(..) */千万不可省略, 否则会很慢)

-- looklock.sql

-- use the NO_MERGE hints can speed up the query

select /*+ NO_MERGE(a) NO_MERGE(b) NO_MERGE(c) */ 'Wait' "Status", a.username, a.machine, a.sid, a.serial#, a.last_call_et "Seconds", b.id1, c.sql_text "SQL"
from v$session a, v$lock b, v$sqltext c
where a.username is not null
and a.lockwait = b.kaddr
and c.hash_value =a.sql_hash_value
union
select /*+ NO_MERGE(a) NO_MERGE(b) NO_MERGE(c) */ 'Lock' "Status", a.username, a.machine, a.sid, a.serial#, a.last_call_et "Seconds", b.id1, c.sql_text "SQL"
from v$session a, v$lock b, v$sqltext c
where b.id1 in
(select /*+ NO_MERGE(d) NO_MERGE(e) */ distinct e.id1
from v$session d, v$lock e
where d.lockwait = e.kaddr)
and a.username is not null
and a.sid = b.sid
and b.request=0
and c.hash_value =a.sql_hash_value;

执行后的结果如下所示:

Stat USERNAME MACHINE SID SERIAL# Seconds ID1

---- ------------------------------ ---------------- --------- --------- --------- ---------

SQL

----------------------------------------------------------------

Lock CIQUSR CIQDULMACER 12 966 245 131089
select * from c_trade_mode for update
Wait CIQUSR CIQDULMACER 10 735 111 131089
update c_trade_mode set x_name = 'zzz' where x_code='5'
Wait CIQUSR CIQDULMACER 15 106 1094 131089
select * from c_trade_mode for update

其中:

Status有两种状态,LOCK表明该进程锁住了某个资源,WAIT表示该进程正在等待某个资源。

Username, Machine分别为ORACLE用户名及机器名

SIDSERIAL#可用于随后的解锁操作

Seconds表示该进程最后一次进行操作至当前的时间()

ID1, 锁标识。某个LOCK状态的ID1与某个WAIT状态的ID1相同,可说明锁的正是另一个进程等待的。

SQL: 锁住资源的SQL语句

2. 解除锁

诊断出锁的状态后,若发现该阻塞其它用户进程的进程是正常操作中,则可通知该用户对其进行提交,从而达到释放锁资源的目的;若为非正常操作,即,其状态为 "inactive",且其Seconds已为较多长时间,则可执行以下语句将该进程进行清除,系统会自动对其进行回滚,从而释放锁住的资源。

alter system kill session 'sid, serial#';

例如: 对于上例中显示的结果, 可用以下语句清除锁住资源的进程:

alter system kill session '12, 966';

关于你所说:在网络断掉(通过拔掉网线)或非正常终止进程(通过task manager强行关闭sql*plus)时,oracle在有限的时间内(我只观查了5-10分)内,oracle未能对该进程作任何处理。

这个处理与TCP协议有关,因为SQL NET在使用TCP/IP协议进行网络连接时是一种短连接,ORACLE连接异常终止时,因为是异常终止,终止信号并没有通过网络通知server端,因此只有下次server有结果从服务器端返回需与client通信时,server才会发现此client已经端掉。因此出现你前面所提ORACLE处理异常终止进程延时情况.

查锁语句:查询产生锁的用户锁sql

select a.username username, a.sid sid, a.serial# serial,b.id1 id1, c.sql_text sqltext
from v$session a, v$lock b, v$sqltext c
where b.id1 in
  
(select distinct e.id1
  
from v$session d, v$lock e
  
where d.lockwait = e.kaddr)
  
and a.sid = b.sid
  
and c.hash_value = a.sql_hash_value
  
and b.request = 0;

一个加速查询锁表和等待锁的方法

--- 这些锁定中有"只读锁""排它锁""共享排它锁"等多种类型,而且每种类型又有"行级锁"(一次锁住一条记录),"页级锁"(一次锁住一页,即数据库中存储记录的最小可分配单元),"表级锁"(锁住整个表)

--- 若为"行级排它锁",则除被锁住的该行外,该表中其它行均可被其它的用户进行修改(update)或删除(delete)操作,若为"表级排它锁",则所有其它用户只能对该表进行查询(select)操作,而无法对其中的任何记录进行修改或删除。当程序对所做的修改进行提交(commit)或回滚后 (rollback)后,锁住的资源便会得到释放,从而允许其它用户进行操作。

oracle 8.0.x 中执行"获取正在等待锁资源的用户名"的查询语句十分缓慢

select a.username, a.sid, a.serial#, b.id1
from v$session a, v$lock b
where a.lockwait = b.kaddr

查找阻塞其它用户的用户进程也十分缓慢

select a.username, a.sid, a.serial#, b.id1
from v$session a, v$lock b
where b.id1 in
(select distinct e.id1
from v$session d, v$lock e
where d.lockwait = e.kaddr)
and a.sid = b.sid
and b.request = 0

一个解决办法。即通过将问题发生时的 v$lockv$session视图中的相关记录保存于自己建立的表中,再对该表进行查询,则速度大大提高,可以迅速发现问题。经实际使用,效果非常好。在接到用户反映后,几秒钟即可查出由于锁住资源而影响其它用户的进程,并进行相应的处理。

首先,以 dba 身份(不一定为system)登录入数据库中,创建三个基本表:my_sessionmy_lock, my_sqltext,并在将会进行查询的列上建立相应的索引。语句如下:

rem v$session 视图中取出关心的字段,创建 my_session ,并在查询要用到的字段上创建索引,以加快查询速度

drop table my_session;
create table my_session
as
select a.username, a.sid, a.serial#,
a.lockwait, a.machine,a.status,
a.last_call_et,a.sql_hash_value,a.program
from v$session a
where 1=2 ;

create unique index my_session_u1 on my_session(sid);
create index my_session_n2 on my_session(lockwait);
create index my_session_n3 on my_session(sql_hash_value);
---- rem
v$lock 视图中取出字段,创建 my_lock 表,并在查询要用到的字段上创建索引,以加快查询速度

drop table my_lock;
create table my_lock
as
select id1, kaddr, sid, request,type
from v$lock
where 1=2;

create index my_lock_n1 on my_lock(sid);
create index my_lock_n2 on my_lock(kaddr);

---- rem v$sqltext 视图中取出字段,创建 my_sqltext 表,并在查询要用到的字段上创建索引,以加快查询速度
drop table my_sqltext;
create table my_sqltext
as
select hash_value , sql_text
from v$sqltext
where 1=2;
create index my_sqltext_n1 on my_sqltext ( hash_value);

-- 然后,创建一个 sql 脚本文件,以便需要时可从 sql*plus 中直接调用。其中,首先用 truncate table 表名命令将表中的记录删除。之所以用 truncate 命令,而不是用delete 命令,是因为delete 命令执行时,将会产生重演记录,速度较慢,而且索引所占的空间并未真正释放,若反复做 insertdelete,则索引所占的空间会不断增长,查询速度也会变慢。而 truncate命令不产生重演记录,速度执行较delete快,而且索引空间被相应地释放出来。删除记录后,再将三个视图中的相关记录插入自己创建的三个表中。最后,对其进行查询,由于有索引,同时由于在插入时条件过滤后,记录数相对来说较少,因而查询速度很快,马上可以看到其结果。

---- 此时,若发现该阻塞其它用户进程的进程是正常操作中,则可通知该用户对其进行提交,从而达到释放锁资源的目的;若为未正常操作,即,其状态为 "inactive",且其last_call_et已为较多长时间,则可执行以下语句将该进程进行清除,系统会自动对其进行回滚,从而释放锁住的资源。

alter system kill session ''sid, serial#''

-- sql 脚本如下:
set echo off
set feedback off
prompt ''
删除旧记录.....''
truncate table my_session;
truncate table my_lock;
truncate table my_sqltext;

prompt ''获取数据.....'
insert into my_session
select a.username, a.sid, a.serial#,
a.lockwait, a.machine,a.status,
a.last_call_et,a.sql_hash_value,a.program
from v$session a
where nvl(a.username,''null'')< >''null”;

insert into my_lock
select id1, kaddr, sid, request,type
from v$lock;

insert into my_sqltext
select hash_value , sql_text
from v$sqltext s, my_session m
where s.hash_value=m.sql_hash_value;

column username format a10
column machine format a15
column last_call_et format 99999 heading "seconds"
column sid format 9999
prompt "
正在等待别人的用户"

select a.sid, a.serial#,
a.machine,a.last_call_et, a.username, b.id1
from my_session a, my_lock b
where a.lockwait = b.kaddr;

prompt "被等待的用户"
select a.sid, a.serial# ,a.machine ,a.last_call_et ,a.username
,b.type ,a.status,b.id1
from my_session a, my_lock b
where b.id1 in
(select distinct e.id1
from my_session d, my_lock e
where d.lockwait = e.kaddr)
and a.sid = b.sid
and b.request=0;

prompt "查出其 sql "
select a.username, a.sid, a.serial#,
b.id1, b.type, c.sql_text
from my_session a, my_lock b, my_sqltext c
where b.id1 in
(select distinct e.id1
from my_session d, my_lock e
where d.lockwait = e.kaddr)
and a.sid = b.sid
and b.request=0
and c.hash_value =a.sql_hash_value;

原文地址:https://www.cnblogs.com/liangqihui/p/297865.html