由delete引起的鎖擴大

由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】,這裏跟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

因此,阿里雲月報中的說法有失偏頗

 

 

本文版權歸作者所有,未經作者同意不得轉載。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章