oracle--数据库锁的问题排查

        Oracle锁表是指对数据库中的表或索引进行加锁,以防止其他事务对其进行修改或访问。Oracle提供了多种锁机制来保证数据库的并发性和数据一致性。但是在Oracle锁表处理不当时,会对数据库的并发性和性能产生一定的影响。

        锁冲突:当多个事务同时尝试对同一个表或索引加锁时,可能会发生锁冲突的情况。如果锁冲突频繁发生,会导致事务等待时间增加,从而影响数据库的性能和可扩展性。

        锁超时:为了防止锁冲突导致系统崩溃,Oracle提供了锁超时的机制。如果一个事务请求某个锁超过规定的时间,Oracle会自动将其杀掉,以释放锁资源。锁超时可能会影响数据库的稳定性和可用性。

         性能下降:锁机制的实现需要一定的开销,会增加数据库的负载。如果锁机制使用不当,可能会导致数据库性能下降,甚至出现死锁的情况。

        以下脚本是在长期的oracle运维工作经验中整理出来的关于数据库锁的查询和优化,当监控到数据库突然的性能抖动,例如CPU、内存使用率突然陡增,SQL执行效率突然降低等情况下,可以参考以下脚本进行数据库锁表或者慢SQL的分析。

1.数据库锁表

--被锁对象表、数据库对象表、数据session表关联来获取被锁对象对应的是哪个session;
select sess.sid,
       sess.serial#,
       lo.oracle_username,
       lo.os_user_name,
       ao.object_name,
       lo.locked_mode
  from gv$locked_object lo, dba_objects ao, gv$session sess
 where ao.object_id = lo.object_id
   and lo.session_id = sess.sid;

select *
  from gv$session t1, gv$locked_object t2
 where t1.sid = t2.SESSION_ID;

--查看导致锁表的sql语句是那一条
select /*+ parallel(16)*/ l.session_id,
       s.serial#,
       l.locked_mode,
       s.event,
       l.oracle_username,
       s.user#,
       l.os_user_name,
       s.machine,
       s.terminal,
       a.sql_text,
       a.action
  from gv$sqlarea a, gv$session s, gv$locked_object l
 where l.session_id = s.sid
   and s.prev_sql_addr = a.address
 order by sid, s.serial#;
--杀掉锁表进程:
--通过上面的查询获取SID和serial#,替换下面的x,y,就可以解除被锁的状态
alter system kill session 'x,y';

2.正在执行的慢SQL情况

/*sql_hash_value=hash_value查询正在执行的sql,prev_hash_value=hash_value查询已经执行过但未释放session的sql*/
select /*+ parallel(8)*/
 b.inst_id,
 b.sid,
 b.serial#,
 c.last_active_time,
 b.event,
 b.BLOCKING_SESSION "被哪个session锁",
 b.type,
 c.sql_text,
 C.SQL_ID,
 b.machine,
 b.username,
 b.osuser,
 b.status,
 'kill -9 ' || a.spid as "kill in os",
 'ALTER SYSTEM KILL SESSION ' || '''' || b.sid || ',' || b.serial# || ',@' ||
 b.inst_id || '''' || ';' as "kill in oracle"
  from gv$process a, gv$session b, gv$sql c
 where a.ADDR = b.PADDR
   and decode(b.sql_hash_value, 0, b.prev_hash_value, b.sql_hash_value) =
       c.hash_value
   and a.INST_ID = b.INST_ID
   and a.INST_ID = c.INST_ID
   and c.SQL_TEXT<>'SELECT 1 FROM DUAL'
   and b.username not in ('GGS','');

3.长事务查询

select /*+ parallel(8)*/
 t1.inst_id,
 t1.sid,
 t1.serial#,
 t1.username,
 t1.machine,
 t2.start_time,
 t1.status,
 t1.event,
 t1.type,
 t3.sql_text,
 t3.SQL_ID,
 'ALTER SYSTEM KILL SESSION ' || '''' || t1.sid || ',' || t1.serial# || ',@' ||
 t1.inst_id || '''' || ';' as "kill in oracle",
 t2.xid
  from gv$session t1, gv$transaction t2, gv$sqlarea t3
 where t1.taddr = t2.addr
   and t1.inst_id = t2.inst_id
   and t3.hash_value =
       decode(t1.sql_hash_value, 0, t1.prev_hash_value, t1.sql_hash_value)
   and t1.inst_id = t3.inst_id
   and t1.username not in ('', '', '')
 order by t2.start_time asc;

4.其他

--如果怀疑表被锁了,或者事务未被正常关闭,在Oracle数据库中我们可以通过以下语句进行查询获取相关信息:
select t2.username,
       t2.sid,
       t2.serial#,
       t3.object_name,
       t2.event,
       t2.OSUSER,
       t2.MACHINE,
       t2.PROGRAM,
       t2.LOGON_TIME,
       t2.COMMAND,
       t2.LOCKWAIT,
       t2.SADDR,
       t2.PADDR,
       t2.TADDR,
       t2.SQL_ADDRESS,
       t1.LOCKED_MODE
  from gv$locked_object t1, gv$session t2, dba_objects t3
 where t1.session_id = t2.sid
   and t1.inst_id = t2.inst_id
   and t1.object_id = t3.object_id
 order by t2.logon_time;
--根据sid查询sql语句
select t1.sid, t1.username, t1.machine, t1.osuser, t1.event, t2.sql_text
  from gv$session t1, gv$sql t2
 where decode(t1.sql_hash_value, 0, t1.prev_hash_value, t1.sql_hash_value) =
       t2.hash_value
   and t1.inst_id = t2.inst_id
   and t1.sid = '20580';
--根据事务id查询sql语句
select t1.sid,
       t1.username,
       t1.machine,
       t1.osuser,
       t1.event,
       t2.sql_text,
       t2.sql_fulltext
  from gv$session t1, gv$sqlarea t2, gv$transaction t3
 where decode(t1.sql_hash_value, 0, t1.prev_hash_value, t1.sql_hash_value) =
       t2.hash_value
   and t1.inst_id = t2.inst_id
	 and t1.TADDR=t3.ADDR
   and t3.XID='9D0709003A670000';
--查询长时间不提交的SQL
select a."INST_ID",
       a."SID",
       a."SERIAL#",
       a."EVENT",
       a."USERNAME",
       a."MACHINE",
       b."SQL_TEXT",
       b."SQL_FULLTEXT"
  from gv$session a, v$sqlarea b
 where a."PREV_HASH_VALUE" != '0'
   and a."SQL_HASH_VALUE" = '0'
   and a."PREV_HASH_VALUE" = b."HASH_VALUE";

猜你喜欢

转载自blog.csdn.net/m0_38004228/article/details/131454988