磐维数据库介绍
磐维数据库,简称"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";




