摘要:当开启transaction,执行updata的语句执行胜利,不执行commit或rollback;再开启另一个窗口,执行upadate语句,会呈现失败(报错:锁期待超时)的状况,然而如果对于上一个窗口执行rollback,此窗口update能够执行胜利,该种状况应思考该表是否为列存表。
本文分享自华为云社区《列存表并发更新时时的锁期待问题原理》,原文作者:PFloyd 。
当开启transaction,执行updata的语句执行胜利,不执行commit或rollback;再开启另一个窗口,执行upadate语句,会呈现失败(报错:锁期待超时)的状况,然而如果对于上一个窗口执行rollback,此窗口update能够执行胜利,该种状况应思考该表是否为列存表。
【问题根因】
如果应用的是列存表,在事务中执行update操作时,是以CU为单位进行加锁的,所以在事务未提交时并发更新同一CU的其余数据时会呈现锁期待的状况,期待超时的时候会呈现报错
【机制原理】
1.CU为压缩单元(Compress Unit),列存储的最小单位,导入数据时生成,生成后数据固定不可更改,单个CU最多存储1列60000行数据。同一列的CU间断存储在一个文件中,当大于1G时,切换到新文件中。其中的Ctid字段标识列存表的一行,由cu_id和CU外行号(cu_id, offset)组成;一次性写入的多条的数据位于同一CU。
2. 为了避免页面同一个元组被两个事务同时更新,在进行update时,都会加上行级锁,对于行存来说是对一行数据加锁,对于列存来说就是对一个CU加锁,当一个事务update未提交时,其余事务是无奈同时去更新同一CU的数据的。
3.进行update操作后,旧元组被标记为deleted,新元组会写到一个新的CU中
【案例剖析】
1.依据现场的报错信息,能够确定是并发更新报错;进行update时,会申请行级锁,在申请行级锁之前会申请transactionid锁,期待超时后报错信息为:waiting for ShareLock on transaction xxx after ..ms
2.客户反馈更新的并不是同一条数据,id不同,询问客户后得悉呈现问题的是列存表,查问更新的数据是否处于同一CU。
查问后发现处于同一CU,合乎预期。
3.本地场景复现:
起事务执行update操作:
事务未提交并发更新数据呈现期待:
查问后发现两条数据位于同一cu:
【相干问题】
为什么update胜利一次之后,下一次update就不会相互等锁了?
这是因为update胜利之后,旧数据被标记为deleted,新数据写入新的CU,这两条数据不再是同一个CU了,也就不存在这种锁抵触
【解决计划】
列存表不适宜频繁的update场景,列存频繁的update容易触发并发更新等锁超时,并且会导致小CU过多,而每个CU都会扩大至8192字节进行对齐,从而导致磁盘空间迅速收缩;频繁的点查或频繁update场景倡议应用行存表。
点击关注,第一工夫理解华为云陈腐技术~