这个是我之前在项目组里面,有一个功能模块写了一个很复杂的sql存储过程,每次做业务都调用存储过来处理逻辑。
当多人同时做业务调用这个存储过程的时候,页面没法响应一直卡死在哪里,后面请教过专业的dba排查过问题,是存储过程里面的某部分insert,update操作导致死锁了。
现在讲排查死锁的步骤总结如下:
1、查行锁:
column event format a30
column sess format a20
set linesize 150
break on id1 skip 1
select decode(request,0,'Holder:',' Waiter:') || s.inst_id || ':' || s.sid||','|| s.serial# sess,
id1, id2, lmode, request, l.type, ctime, s.sql_id, s.event,s.last_call_et
from gv$lock l, gv$session s
where (id1, id2, l.type) in
(select id1, id2, type from gv$lock where request>0)
and l.sid=s.sid
and l.inst_id=s.inst_id
order by id1, ctime desc, request;
2、通过查行锁定位出来存储过程里面是哪些sql导致的死锁:
导致锁表的sqlId:
select sql_text from gv$sql where sql_id='9g5813my4anbt'; 这个是查具体sql语句
一下为死锁相关的表,通过dba权限去查看:
SELECT * FROM v$lock;
SELECT * FROM v$sqlarea;
SELECT * FROM v$session;
SELECT * FROM v$process ;
SELECT * FROM v$locked_object;
SELECT * FROM all_objects;
SELECT * FROM v$session_wait;
--查看被锁的表
select b.owner,b.object_name,a.session_id,a.locked_mode from v$locked_object a,dba_objects b where b.object_id = a.object_id;
--查看那个用户那个进程照成死锁
select b.username,b.sid,b.serial#,logon_time from v$locked_object a,v$session b where a.session_id = b.sid order by b.logon_time;
--查看连接的进程
SELECT sid, serial#, username, osuser FROM v$session;
--3.查出锁定表的sid, serial#,os_user_name, machine_name, terminal,锁的type,mode
SELECT s.sid, s.serial#, s.username, s.schemaname, s.osuser, s.process, s.machine,
s.terminal, s.logon_time, l.type
FROM v$session s, v$lock l
WHERE s.sid = l.sid
AND s.username IS NOT NULL
ORDER BY sid;
这个语句将查找到数据库中所有的DML语句产生的锁,还可以发现,
任何DML语句其实产生了两个锁,一个是表锁,一个是行锁。
--杀掉进程 sid,serial#
4、最后的解决办法就是要去优化存储过程,或者从业务方面就行优化才得到解决,我们当时对几张几千万数据的大表做了表分区处理,按年份把不同年份的数据落到
不同的数据文件里面,希望通过我真实遇到的问题以及解决的技术方案对大家有所帮助!