糟糕!核心业务锁表,抓瞎了?
作者:IT邦德
中国DBA联盟(ACDU)成员,10余年DBA工作经验,
Oracle、PostgreSQL ACE
CSDN博客专家及B站知名UP主,全网粉丝10万+
擅长主流Oracle、MySQL、PG、
高斯及Greenplum备份恢复,
安装迁移,性能优化、故障应急处理
微信:jem_db
QQ交流群:587159446
公众号:IT邦德
@
-
1.锁表产生的场景
-
2.Oracle案例
-
2.1 排查锁的发生
-
2.2 Oracle解锁
-
3.MySQL案例
-
3.1 查看当前锁表事务
-
3.2 锁的释放
-
4.总结
前言
近期系统在使用过程中突发了几次数据库锁表情况,做个总结,避免以后在出现,大家忙手忙脚的
1.锁表产生的场景
数据库锁表通常发生在以下几种场景中:
1.DML操作:在执行INSERT、UPDATE、DELETE等数据操纵语言(DML)操作时,
如果涉及的数据行已经被其他事务锁定,
当前操作可能会等待锁释放,从而导致锁表
2.DDL操作:使用ALTER TABLE、TRUNCATE TABLE
等数据定义语言(DDL)语句对表进行结构性修改时,
需要锁定整个表以防止其他会话对表进行操作,这可能导致锁表
3.索引缺失或不当使用:如果UPDATE语句或DELETE语句的WHERE条件没有走索引,
或者查询时使用的索引不可用,
可能会导致锁表,因为数据库可能会选择使用表锁而不是行锁。
4.长事务或大事务:当一个事务长时间占用锁资源或操作大量数据时,
可能会导致其他事务等待锁释放,从而形成锁表。
5.死锁:当多个事务相互等待对方释放锁时,
可能会产生死锁,导致锁表问题。
6.并发操作:在高并发场景下,
如果多个事务同时尝试修改同一资源,可能会导致锁表。
2.Oracle案例
2.1 排查锁的发生
--通过以下的SQL找出阻塞的seesion
select * from dba_hist_active_sess_history a
where a.sample_time between
to_date('202008011230', 'yyyymmddhh24mi')
and to_date('202012121230', 'yyyymmddhh24mi');
BLOCKING_SESSION:阻塞会话的ID
CURRENT_OBJ#:会话当前引用的对象的对象ID
使用DBA_HIST_ACTIVE_SESS_HISTORY可以帮助DBA跟踪和调试数据库性能问题,
了解会话的行为和影响,在排查行锁中非常实用。
定位SQL
select CPU_COST,IO_COST,COST from v$sql_plan
where sql_id='6qd38pjx143g0';
select sql_id,sql_text from v$sql where sql_text
where sql_id='6qd38pjx143g0';
定位被锁的对象
select * from dba_objects where object_id=4333
2.2 Oracle解锁
SELECT SESS.SID,
SESS.SERIAL#,
LO.ORACLE_USERNAME,
LO.OS_USER_NAME,
AO.OBJECT_NAME 被锁对象名,
LO.LOCKED_MODE 锁模式,
sess.LOGON_TIME 登录数据库时间,
'ALTER SYSTEM KILL SESSION '''
|| SESS.SID || ','||SESS.SERIAL#||'''' FREESQL
FROM V$LOCKED_OBJECT LO, DBA_OBJECTS AO, V$SESSION SESS
WHERE AO.OBJECT_ID = LO.OBJECT_ID
AND LO.SESSION_ID = SESS.SID
ORDER BY sid, sess.serial#;
通过此sql可以查询到以下内容:
复制完执行可能会报错:ORA-00031: session marked for kill,这表示ORACLE已经把它标记为一个杀死的进程,但暂时无法将其彻底杀死,这个时候需要我们执行下面的sql,查出它在服务器上的进程id:
# sid 为上面sql 查出来的 sid
select spid, osuser, s.program
from v$session s,v$process p
where s.paddr=p.addr
and s.sid='24986'
通过上方 sql 可以得到服务器上的进程 id,登录数据库所在服务器,利用 kill 命令将其杀死即可:
kill -9 12009(查出来的spid)
3.MySQL案例
3.1 查看当前锁表事务
查看是否锁表SQL语句
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
SHOW OPEN TABLES WHERE `Table` = 'table_name'
AND `Database` = 'database_name';
3.2 锁的释放
MySQL中锁的释放是自动进行的,当一个会话执行完相关操作后,所持有的锁会自动释放。不过,有些情况下我们可能需要手动释放锁,比如长事务或者死锁的处理。
4.总结
为了避免锁表,可以采取优化SQL语句、合理使用索引、减少事务的持有时间、使用事务隔离级别、分离读写操作等措施。在生产环境中,还应该实施监控和警报机制,以便及时发现并处理锁表问题。