由delete语句引起的锁范围扩大
阿里云月报中的一句话,出处:http://mysql.taobao.org/monthly/2022/01/01/
但是Ghost Record是可以跟正常的Record一样作为Key Range Lock的加锁对象的。可以看出这相当于把删除操作变成了更新操作,因此删除事务不再需要持有Next Key Lock
这句话意思是:假设delete语句物理删除数据,那么delete事务会持有gap lock,那么会造成锁扩大,而实际上delete操作会转为update操作,最终delete事务持有的gap lock退化为record lock,不会造成锁范围扩大
下面用SQL Server和MySQL做测试,看一下锁的情况
SQL Server 2012
use test go
CREATE TABLE t ( id int NOT NULL primary key, c int DEFAULT NULL, d int DEFAULT NULL ) CREATE NONCLUSTERED INDEX [ix_t_c] ON [dbo].[t] ( [c] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO insert into t values(5,5,5),(10,10,10),(20,20,20),(25,25,25);
使用下面的执行顺序
在session1执行下面语句
--session 1
USE test
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE GO begin transaction select id from t where c >10 and c <= 24 delete from t where c = 25 --commit
在session2执行下面语句
--session 2
USE test
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE GO insert into t(id,c,d) values(27,27,27); --(blocked)
申请的锁,情况如下
分析:首先我们要关注的加锁对象是二级索引【ix_t_c】,可以看到有三个range锁,这里锁住的范围是
rangeS-S(10,20]
rangeX-X(20, 25]
rangeS-U[25, +∞) 正无穷
正因为rangeS-U 锁,session 2的insert操作被阻塞了,也就是删除 c=25 这行数据,导致键范围锁扩大到 正无穷
MySQL 8.0.28
set global transaction isolation level REPEATABLE READ; select @@global.transaction_isolation; use test; CREATE TABLE `t` ( `id` int(11) NOT NULL, `c` int(11) DEFAULT NULL, `d` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `c` (`c`) ) ENGINE=InnoDB; insert into t values(5,5,5),(10,10,10),(20,20,20),(25,25,25);
SQL语句执行顺序跟SQL Server一样
在session1执行下面语句
-- session 1
begin;
select id from t where c >10 and c <= 24 for update; delete from t where c = 25; --commit
在session2执行下面语句
-- session 2
insert into t(id,c,d) values(27,27,27); --(blocked)
申请的锁,情况如下
select * from performance_schema.data_locks\G
*************************** 1. row ***************************
ENGINE: INNODB
ENGINE_LOCK_ID: 140111552409600:1217:140111564061632 ENGINE_TRANSACTION_ID: 7643 THREAD_ID: 331 EVENT_ID: 8 OBJECT_SCHEMA: test OBJECT_NAME: t PARTITION_NAME: NULL SUBPARTITION_NAME: NULL INDEX_NAME: NULL OBJECT_INSTANCE_BEGIN: 140111564061632 LOCK_TYPE: TABLE LOCK_MODE: IX LOCK_STATUS: GRANTED LOCK_DATA: NULL *************************** 2. row *************************** ENGINE: INNODB ENGINE_LOCK_ID: 140111552409600:59:5:1:140111564058528 ENGINE_TRANSACTION_ID: 7643 THREAD_ID: 331 EVENT_ID: 8 OBJECT_SCHEMA: test OBJECT_NAME: t PARTITION_NAME: NULL SUBPARTITION_NAME: NULL INDEX_NAME: c OBJECT_INSTANCE_BEGIN: 140111564058528 LOCK_TYPE: RECORD LOCK_MODE: X,INSERT_INTENTION LOCK_STATUS: WAITING LOCK_DATA: supremum pseudo-record *************************** 3. row *************************** ENGINE: INNODB ENGINE_LOCK_ID: 140111552408792:1217:140111564055552 ENGINE_TRANSACTION_ID: 7642 THREAD_ID: 330 EVENT_ID: 12 OBJECT_SCHEMA: test OBJECT_NAME: t PARTITION_NAME: NULL SUBPARTITION_NAME: NULL INDEX_NAME: NULL OBJECT_INSTANCE_BEGIN: 140111564055552 LOCK_TYPE: TABLE LOCK_MODE: IX LOCK_STATUS: GRANTED LOCK_DATA: NULL *************************** 4. row *************************** ENGINE: INNODB ENGINE_LOCK_ID: 140111552408792:59:5:1:140111564052496 ENGINE_TRANSACTION_ID: 7642 THREAD_ID: 330 EVENT_ID: 12 OBJECT_SCHEMA: test OBJECT_NAME: t PARTITION_NAME: NULL SUBPARTITION_NAME: NULL INDEX_NAME: c OBJECT_INSTANCE_BEGIN: 140111564052496 LOCK_TYPE: RECORD LOCK_MODE: X LOCK_STATUS: GRANTED LOCK_DATA: supremum pseudo-record *************************** 5. row *************************** ENGINE: INNODB ENGINE_LOCK_ID: 140111552408792:59:5:4:140111564052496 ENGINE_TRANSACTION_ID: 7642 THREAD_ID: 330 EVENT_ID: 12 OBJECT_SCHEMA: test OBJECT_NAME: t PARTITION_NAME: NULL SUBPARTITION_NAME: NULL INDEX_NAME: c OBJECT_INSTANCE_BEGIN: 140111564052496 LOCK_TYPE: RECORD LOCK_MODE: X LOCK_STATUS: GRANTED LOCK_DATA: 20, 20 *************************** 6. row *************************** ENGINE: INNODB ENGINE_LOCK_ID: 140111552408792:59:5:5:140111564052496 ENGINE_TRANSACTION_ID: 7642 THREAD_ID: 330 EVENT_ID: 12 OBJECT_SCHEMA: test OBJECT_NAME: t PARTITION_NAME: NULL SUBPARTITION_NAME: NULL INDEX_NAME: c OBJECT_INSTANCE_BEGIN: 140111564052496 LOCK_TYPE: RECORD LOCK_MODE: X LOCK_STATUS: GRANTED LOCK_DATA: 25, 25 *************************** 7. row *************************** ENGINE: INNODB ENGINE_LOCK_ID: 140111552408792:59:4:4:140111564052840 ENGINE_TRANSACTION_ID: 7642 THREAD_ID: 330 EVENT_ID: 12 OBJECT_SCHEMA: test OBJECT_NAME: t PARTITION_NAME: NULL SUBPARTITION_NAME: NULL INDEX_NAME: PRIMARY OBJECT_INSTANCE_BEGIN: 140111564052840 LOCK_TYPE: RECORD LOCK_MODE: X,REC_NOT_GAP LOCK_STATUS: GRANTED LOCK_DATA: 20 *************************** 8. row *************************** ENGINE: INNODB ENGINE_LOCK_ID: 140111552408792:59:4:5:140111564052840 ENGINE_TRANSACTION_ID: 7642 THREAD_ID: 330 EVENT_ID: 12 OBJECT_SCHEMA: test OBJECT_NAME: t PARTITION_NAME: NULL SUBPARTITION_NAME: NULL INDEX_NAME: PRIMARY OBJECT_INSTANCE_BEGIN: 140111564052840 LOCK_TYPE: RECORD LOCK_MODE: X,REC_NOT_GAP LOCK_STATUS: GRANTED LOCK_DATA: 25 8 rows in set (0.00 sec)
分析:这里我们要关注的加锁对象依然是二级索引【c】,这里MySQL的情况跟SQL Server一样
LOCK_MODE: X
LOCK_STATUS: GRANTED
LOCK_DATA: supremum pseudo-record
锁住的范围是 [25, +∞) 正无穷, 所以session 2的insert操作被阻塞了,也就是删除 c=25 这行数据,导致gap lock 扩大到 正无穷
通过上面两个测试,可以知道,即使delete操作在数据表中留下了Ghost Records,但是delete事务造成的gap lock范围没有缩小为Ghost Record的 record lock
因此,阿里云内核月报中的说法有失偏颇,误导读者
本文版权归作者所有,未经作者同意不得转载。
,
本文版权归作者所有,未经作者同意不得转载。
1.本站内容仅供参考,不作为任何法律依据。用户在使用本站内容时,应自行判断其真实性、准确性和完整性,并承担相应风险。
2.本站部分内容来源于互联网,仅用于交流学习研究知识,若侵犯了您的合法权益,请及时邮件或站内私信与本站联系,我们将尽快予以处理。
3.本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
4.根据《计算机软件保护条例》第十七条规定“为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。”您需知晓本站所有内容资源均来源于网络,仅供用户交流学习与研究使用,版权归属原版权方所有,版权争议与本站无关,用户本人下载后不能用作商业或非法用途,需在24个小时之内从您的电脑中彻底删除上述内容,否则后果均由用户承担责任;如果您访问和下载此文件,表示您同意只将此文件用于参考、学习而非其他用途,否则一切后果请您自行承担,如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
5.本站是非经营性个人站点,所有软件信息均来自网络,所有资源仅供学习参考研究目的,并不贩卖软件,不存在任何商业目的及用途
暂无评论内容