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";