【熟能生巧】查看Oracle DB Lock及快速处理 - 上篇
问题
在开发时,遇到一个问题,我运行了一个简单的 update 语句如下:
update table_a set column_b = 'something' where condition_c = 'blablabla';
但是,执行了很久都没有完成。等了大概有 5 分钟,还在 run 。这个表不是很大,写入也不多,平时都是秒杀的。
分析长时间运行的语句
首先,看一下现在有没有 long running sql 。
-- check long running sql
select ses.osuser, nvl(ses.username,'ORACLE PROC')||' ('||ses.sid||')'
username, sid, machine, replace(sql.sql_text,chr(10),'') stmt,
ltrim(to_char(floor(ses.last_call_et/3600), '09')) || ':' ||
ltrim(to_char(floor(mod(ses.last_call_et, 3600)/60), '09')) || ':' ||
ltrim(to_char(mod(ses.last_call_et, 60), '09')) runt
from v$session ses, v$sqltext_with_newlines sql
where ses.status = 'ACTIVE'
and ses.username is not null
and ses.sql_address = sql.address
and ses.sql_hash_value = sql.hash_value
and ses.audsid <> userenv('SESSIONID')
order by runt desc, 1,sql.piece;
结果 ->
OSUSER USERNAME SID MACHINE STMT RUNT
oracle SCEMA_A (1111) 1111 machine.a.ip update table_a ...; 10:00:00
oracle SCEMA_A (2222) 2222 machine.b.ip update table_a ...; 12:00:00
果然有,而且,也是 update 这个 table_a ,且已经跑了10几个小时了。
由此判断,应该是这个表被锁住了,所以 block 了其它想要 update 的语句。
查看锁
使用如下语句查看锁:
-- check lock
select
(select username from v$session where sid=a.sid) blocker,
a.sid,
' is blocking ',
(select username from v$session where sid=b.sid) blockee,
b.sid
from
v$lock a,
v$lock b
where
a.block = 1
and
b.request > 0
and
a.id1 = b.id1
AND
A.ID2 = B.ID2;
结果 ->
BLOCKER SID ISBLOCKING BLOCKEE SID_1
SCEMA_A 3333 is blocking SCEMA_A 1111
SCEMA_A 3333 is blocking SCEMA_A 2222
果然,发现 SID 为 3333 的这个进程, block 住了 1111 和 2222 。
进一步,我们来看看这个进程是谁跑的。
SELECT SES.USERNAME, SES.OSUSER, SES.PROGRAM, SQL.SQL_TEXT
FROM V$SESSION SES, V$SQLTEXT_WITH_NEWLINES SQL
WHERE SES.SID = 428
AND SES.SQL_ADDRESS = SQL.ADDRESS
AND SES.SQL_HASH_VALUE = SQL.HASH_VALUE;
结果 ->
USERNAME OSUSER PROGRM SQL_TEXT
SCEMA_A user_aaa SQL Developer something
SCEMA_A user_aaa SQL Developer something
SCEMA_A user_aaa SQL Developer something
可以看出,这个 3333 是 user_aaa 跑的。但是目前他并没有 run 相关的 update table_a 的 query 。
解决
和 user_aaa 讨论过后,知道,原来他之前跑了一句 update table_a ,但是没有 commit ,于是他的 session 一直拿着这个锁。
让他 commit 一下就好了,锁马上被释放,其它的语句也可以顺利执行完成。
如果 user_aaa 不在,联系不上咋办呢,把他的 session kill 掉,这个锁也会被释放。
ALTER SYSTEM KILL SESSION '<3333, 36575>';
参考
- Finding oracle locked objects http://www.dba-oracle.com/t_find_oracle_locked_objects.htm
- Terminating Sessions and Cleaning Up Processes https://www.oracle.com/ocom/groups/public/@otn/documents/webcontent/283689.htm
- Locks not getting released even after the session is killed https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:4070311835620