等待事件含义
Lock:在数据库管理系统中,锁是用来确保数据完整性和一致性的重要机制。当一个事务需要修改数据时,它会请求一个锁来防止其他事务同时修改相同的数据,从而导致数据不一致。
transactionid:这通常是一个唯一标识符,用于区分和跟踪数据库中的不同事务。每个事务都有一个唯一的ID,这样系统就可以知道哪些操作属于同一个事务,哪些操作属于不同的事务。
等待:当一个事务尝试获取一个锁但发现该锁已经被另一个事务持有时,它就会进入等待状态。这意味着该事务会暂停其操作,直到锁被释放。这确保了并发操作之间的顺序性和一致性。
出现这个Lock:transactionid等待事件原因往往和业务逻辑有关系。
等待时间增加的可能原因
等待事件Lock:transactionid发生在当一个事务试图获取一个行级锁,而这个锁已经被已经运行的另一个事务授予。显示 Lock:transactionid 等待事件的会话由于这个锁而被阻塞。在阻塞事务中 COMMIT 或 ROLLBACK 语句结束时,被阻塞的事务可以继续进行。通常涉及并发控制和事务管理的场景。
KES的的多版本并发控制(MVCC)保证了事务中读不会阻塞写,写也不会阻塞读。对于行级冲突的发生,阻塞和被阻塞的事务必然发生在以下类型的冲突语句:
UPDATE 加对应行级锁,这意味着其他事务不能同时修改或锁定相同的行,直到原事务提交或回滚。
SELECT ... FOR UPDATE 阻止其他事务修改或锁定所选的行。
SELECT ... FOR KEY SHARE 阻止其他事务进行 UPDATE、DELETE 或 SELECT ... FOR UPDATE 操作,但允许使用 SELECT ... FOR KEY SHARE 或仅读取这些行。
不同的sql语句会对应不同的锁类型。
参考锁机制文章:https://www.cnblogs.com/kingbase/p/15911906.html
高并发
KES 可以使用细粒度的行级锁。当并发性增加时,多事务间行级锁冲突的概率会增加,他们之间会竞争相同的行级锁:
空闲事务
有时,sys_stat_activity.state 列会显示值 idle in transaction。这个值发生在已经启动了一个事务但尚未发出 COMMIT 或 ROLLBACK 的会话中。如果 sys_stat_activity.state 的值不是 active,对应显示的查询是最近一个已经完成的查询。
如果一个空闲的事务获取了行级锁,它可能会阻止其他会话获取该锁。这种情况会导致 Lock:transactionid 等待事件频繁发生。为了诊断问题,我们可以监控kwr报告中的等待事件部分。
解决方法
行锁是UPDATE、SELECT ... FOR UPDATE或SELECT ... FOR KEY SHARE等语句之间的冲突。先找出业务运行期间行锁阻塞信息,解决阻塞源问题。
相关sql查询语句:
SELECT
sys_locks.pid,
a.datname,
locktype,
virtualtransaction,
transactionid,
nspname,
relname,
mode,
granted,
cast(date_trunc('second',query_start) AS timestamp) AS query_start
FROM
sys_locks
LEFT OUTER JOIN sys_class ON (sys_locks.relation = sys_class.oid)
LEFT OUTER JOIN sys_namespace ON (sys_namespace.oid = sys_class.relnamespace),
sys_stat_activity a
WHERE NOT sys_locks.pid = sys_backend_pid()
AND sys_locks.pid=a.pid
and sys_class.relname='';
应对高并发,可以尝试以下方法
在应用中降低并发量。例如,减少活动会话的数量,使用连接池管理连接数,并发数。
重新设计应用程序的业务逻辑避免争用的UPDATE和SELECT … FOR UPDATE等语句,还可以减少SELECT … FOR KEY SHARE语句的访问。
处理空闲事务
如果sys_stat_activity.state显示为空闲事务(idle in transaction),请使用以下方法:
尽可能开启自动提交(autocommit,默认开启,查看方式:\echo :AUTOCOMMIT)。这种方法可以防止事务在等待COMMIT或ROLLBACK时阻塞其他事务。
在数据库或应用程序级别设置事务超时,确保空闲事务在达到某个时间限制后被自动终止,例如在数据库设置参数idle_in_transaction_session_timeout。
处理长时间运行的事务
长时间运行的事务可能导致频繁出现“Lock:transactionid”的问题,
在长时间运行的事务中避免使用行锁,解决阻塞源,然后排查业务逻辑,协商应用人员对其进行修改。
使用数据库的EXPLAIN ANALYZE命令来查看查询sql的执行计划,并找出可能的性能瓶颈。
如果可能,将大事务分割成多个小事务。
在应用程序级别或连接池设置事务超时参数,以确保长时间运行的事务在达到某个时间限制后被自动终止,但这个方法不是最优选择。