共计 1247 个字符,预计需要花费 4 分钟才能阅读完成。
摘要:当开启 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 场景倡议应用行存表。
点击关注,第一工夫理解华为云陈腐技术~