暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

磐维数据库出现锁超时如何处理“ERROR: Lock wait timeout”

原创 王贝 2025-04-01
342

磐维数据库介绍

磐维数据库,简称"PanWeiDB"。是中国移动信息技术中心首个基于中国本土开源数据库打造的面向ICT基础设施的自研数据库产品。其产品内核能力基于华为openGauss开源软件,并进一步提升了系统稳定性。 磐维数据库具有高性能、高可靠、高安全、高兼容等特点,能够满足复杂多变的业务需求。磐维数据库提供了自动化、流程化的解决方案,实现了一键式数据迁移。这种高效的数据迁移方式不仅提高了迁移数据的效率,也降低了操作难度,为用户带来了极大的便利。

问题现象:

执行dml sql报以下错误

postgres=# update db2instl.bt_user set password='51DD63578F560E7C1AB37CCB3EAB3FD1' where user_code='F75C0201' ;

ERROR: Lock wait timeout: thread 23251466581760 on node dn_6001_6002_6003 waiting for ShareLock on transaction 24475665 after 60000.316 ms
DETAIL: blocked by hold lock thread 23242944669440, statement <select A.ID ,A.OFFICE_CODE,A.BUSI_DATE from BT_AUDIT_OFFICE_DAILLY_DATA_NEW A WHERE A.CHARGE_MONEY=0 and A.BUSI_DATE =$1 and A.is_zhazhang =$2>, hold lockmode ExclusiveLock.

疑点:dml操作被阻塞,为什么阻塞源显示的sql是select语句?

快速处理方法:

1、查找阻塞会话信息

with tl as (select usename,a.pid,granted,locktag,query_start,query from pg_locks l,pg_stat_activity a
where l.pid=a.pid and locktag in(select locktag from pg_locks where granted='f'))
select ts.usename locker_user,ts.pid locker_user_pid,ts.query_start locker_query_start,ts.granted locker_granted,ts.query locker_query,tt.query locked_query,tt.query_start locked_query_start,tt.granted locked_granted,tt.usename locked_user,tt.pid locked_user_pid,extract(epoch from now() - tt.query_start) as locked_times
from (select * from tl where granted='t') as ts,(select * from tl where granted='f') tt
where ts.locktag=tt.locktag order by 2;

2、跟业务确认是否杀掉阻塞会话

SELECT pg_terminate_backend(pid);

问题分析:

 现象:
数据库存在未提交的长事务,业务update出现锁超时,此时在数据库中并未查到相关表的锁或者阻塞信息,只是查到了一个与目标表不相关的select语句,将该select会话结束后,update锁表问题解决。

dml操作被阻塞,为什么阻塞源显示的sql是select语句?
原因:
select所在的空闲事务未提交,数据库的策略是查询锁信息时只显示当前事务中最新的一条DDL、DML或者DQL语句,因此该事务中肯定在select语句之前存在与目标表相关联的DML语句且未提交;数据库开启log_statement=all参数才能记录所有执行过的sql,由于开启这个参数对数据库性能有一定的影响,生产环境不建议配置此参数,所以无法定位到是哪个sql产生的阻塞。

模拟实验:

实验数据:

开启日志记录:

gs_guc reload -N all -I all -c "log_statement=all";       #此参数对数据库性能有一定的影响,用完后需要关闭

session1:

ysjh=# begin;
ysjh=# update test set name='test1' where id=1;


session2:

ysjh=# update test set name= 'haha1' where id=1;



session1 查询:
ysjh=# select * from test12;

sesson3 查询阻塞

ysjh=# with tl as (select usename,a.pid,granted,locktag,query_start,query from pg_locks l,pg_stat_activity a
where l.pid=a.pid and locktag in(select locktag from pg_locks where granted='f'))
select ts.usename locker_user,ts.pid locker_user_pid,ts.query_start locker_query_start,ts.granted locker_granted,ts.query locker_query,tt.query locked_query,tt.query_start locked_query_start,tt.granted locked_granted,tt.usename locked_user,tt.pid locked_user_pid,extract(epoch from now() - tt.query_start) as locked_times
from (select * from tl where granted='t') as ts,(select * from tl where granted='f') tt
where ts.locktag=tt.locktag order by 2;

根据locker_user_pid在pg_log日志搜索执行过的sql就能找到真正阻塞源sql。

关闭日志记录:

gs_guc reload -N all -I all -c "log_statement=none";

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论