您的位置:首页 > 数据库 > Oracle

怎样快速查出Oracle数据库中的锁等待

2011-03-07 20:06 316 查看
起原:网海拾贝

---- 在大年夜型数据库体系中,为了保证数据的一概性,在对数据库中的数据截止操作时,体系会截止对数据响应的锁定。

---- 这些锁定中有"只读锁"、"排它锁","共享排它锁"等多种范例,而且每种范例又有"行级锁"(一次锁住一笔记录),"页级锁"(一次锁住一页,即数据库中存储记录的最小可分拨单位),"表级锁"(锁住整个表)。

---- 若为"行级排它锁",则除被锁住的该行外,该表中别的行均可被别的的用户截止修改(Update)或删除(delete)操作,若为"表级排它锁",则完全别的用户只能对该表截止盘问(select)操作,而无法对个中的任何记录截止修改或删除。当顺序对所做的修改革行提交(commit)或回滚后(rollback)后,锁住的本钱便会掉掉开释,从而容许别的用户截止操作。

---- 可是,偶然,由于顺序中的缘故原由,锁住本钱后永劫间未对其事情截止提交;或是由于用户的缘故原由,如调出需求修改的数据后,未及时修改并提交,而是安置于一旁;或是由于客户效劳器体例中客户端呈现"死机",而效劳器端却并未检测到,从而形成锁定的本钱未被及时开释,影响到别的用户的操作。

---- 因此,怎样火速地诊断出锁住本钱的用户以及措置其锁定即是数据库治理员的一个寻衅。

---- 由于数据库使用体系越来越庞大, 一旦呈现由于锁本钱未及时开释的景遇,便会惹起对一相反表截止操作的少量用户无法截止操作,从而影响到体系的运用。此时,DBA应尽量快地措置标题问题。可是,由于在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

---- 十分迟缓,(在 Oracle 7.3.4中尝试很快),而且,尝试"查找壅塞别的用户的用户进程"的盘问语句
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$session 中形态为"inactive"(不举止)而且最后一次截止操作时间至当前已赶过 20 分钟以上(last_call_et>20*60 秒)的用户进程清除,然后才使得标题问题得处措置。
---- 可是,这种体例实践上是"把婴儿与脏水一路泼掉"。由于,有些用户的进程虽然也为"inactive",而且也已有较永劫间未举止,可是,那是由于他们处于锁等待形态。

---- 因此,我想出了一个措置措施。即经由进程将标题问题发作时的 v$lock,v$session视图中的关连记录保管于自己树立的表中,再对该表截止盘问,则速度大年夜大年夜进步,可以火速发现标题问题。经实践运用,成效十分好。在接到用户回响后,几秒钟即可查出由于锁住本钱而影响别的用户的进程,并截止响应的措置。

---- 首先,以 dba 身份(不肯定为system)登录入数据库中,创建三个基础表:my_session,my_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 呼吁尝试时,将会产生重演记录,速度较慢,而且索引所占的空间并未真正开释,若反复做 insert及delete,则索引所占的空间会时时增长,盘问速度也会变慢。而 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. 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;

---- 以上思绪也可用于别的大年夜型数据库体系如 Informix, Sybase,DB2中。经由进程运用该剧本,可以极大年夜地进步获取体系中当前锁等待的景遇,从而及时措置数据库使用体系中的锁等待标题问题。而且,由于实践上已掏出其 program 名及响应的 sql 语句,故可以在过后将其记录上去,交给其开发职员截止剖析并从基础上得处措置。

版权声明:
原创作品,容许转载,转载时请务必以超链接体式格局标明文章 原始情由 、作者信息和本声明。不然将清查法律责任。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: