MySQL普通索引的加鎖


前言

前面已經介紹了主鍵索引的加鎖范圍和非主鍵唯一索引的加鎖范圍。

主鍵索引:

  1. 加鎖時,會先給表添加意向鎖,IX 或 IS;
  2. 加鎖是如果是多個范圍,是分開加了多個鎖,每個范圍都有鎖;(這個可以實踐下 id < 20 的情況)
  3. 主鍵等值查詢,數據存在時,會對該主鍵索引的值加行鎖 X,REC_NOT_GAP
  4. 主鍵等值查詢,數據不存在時,會對查詢條件主鍵值所在的間隙添加間隙鎖 X,GAP
  5. 主鍵等值查詢,范圍查詢時情況則比較復雜:
    1. 8.0.17 版本是前開后閉,而 8.0.18 版本及以后,修改為了前開后開區間;
    2. 臨界 <= 查詢時,8.0.17 會鎖住下一個 next-key 的前開后閉區間,而 8.0.18 及以后版本,修復了這個 bug。

非主鍵唯一索引:

  1. 非主鍵唯一索引等值查詢,數據存在,for update 是會在主鍵加鎖的,而 for share 只有在走覆蓋索引的情況下,會僅在自己索引上加鎖;
  2. 非主鍵索引等值查詢,數據不存在,無論是否索引覆蓋,相當於一個范圍查詢,僅僅會在非主鍵索引上加鎖,加的還是間隙鎖,前開后開區間;
  3. 在非主鍵唯一索引范圍查詢時,不是覆蓋索引的時候,會對相應的范圍加前開后閉區間,並且如果存在數據,會對對應的主鍵加行鎖;
  4. 在非主鍵唯一索引范圍查詢時,如果是覆蓋索引時,會對所有的后閉區間對應的主鍵,加行鎖;
  5. 在非主鍵唯一索引加鎖時,還是存在 next-key 鎖住下一個區間的 bug。

這篇文章來一起看一下普通索引和普通字段的加鎖范圍是什么?

數據庫表數據

CREATE TABLE `t` (
  `id` int NOT NULL COMMENT '主鍵',
  `a` int DEFAULT NULL COMMENT '唯一索引',
  `c` int DEFAULT NULL COMMENT '普通索引',
  `d` int DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_a` (`a`),
  KEY `idx_c` (`c`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

數據庫數據如下:

思路和非主鍵唯一索引相同,只不過唯一的區別是這里看的是 c 和 d 字段。

因為前面小伙伴對 data_locks 應該有了一定的了解,這里就直接分析 data_locks 的數據信息。

普通索引

普通索引等值查詢 —— 數據存在

mysql> begin; select * from t where c = 210 for update;

直接分析 data_locks

  1. 表意向鎖;
  2. 索引 idx_c 上添加了 210 區間的前開后閉鎖;
  3. 索引 idx_c 上添加了 215 區間的間隙鎖,LOCK_MODE 為 X,GAP
  4. 主鍵上添加了 15 的行鎖 ,LOCK_MODE 為 X,REC_NOT_GAP

主要是因為普通索引不能唯一鎖定一條記錄,所以要鎖定該字段的前后范圍。

普通索引等值查詢 —— 數據不存在

mysql> begin; select * from t where c = 211 for update;

直接分析 data_locks

  1. 表意向鎖;
  2. 索引 idx_c 上添加了 215 區間的間隙鎖。

分析是因為數據不存在,只需要鎖住 215 間隙就可以了,因為 215 和 210 肯定不屬於這個范圍。

普通索引范圍查詢

mysql> begin; select * from t where c > 210 and c <= 215 for update;

對於鎖住 idx_c 索引的 215 的前開后閉區間是可以理解的,但是鎖住了 220 就不太理解了,應該也是那個 bug 沒有完全修復。

普通字段

普通字段就更好理解了。

對普通字段而言,無論是哪個查詢,都需要掃描全部記錄,所以這個鎖直接加在了主鍵上,並且是鎖住全部的區間。

總結

本文在基於第一篇和第二篇的基礎上,直接通過分析 data_locks 的信息,進行判斷加鎖范圍。

select * from performance_schema.data_locks;
LOCK_MODE LOCK_DATA 鎖范圍
X,REC_NOT_GAP 15 15 那條數據的行鎖
X,GAP 15 15 那條數據之前的間隙,不包含 15
X 15 15 那條數據的間隙,包含 15
  1. LOCK_MODE = X 是前開后閉區間;
  2. X,GAP 是前開后開區間(間隙鎖);
  3. X,REC_NOT_GAP 行鎖。

從而得出普通索引和普通字段的結論。

普通索引

  1. 普通索引等值查詢,因為不能確定唯一性,所以即使定位到記錄,也是會向后查詢,直到查詢到不為該值的記錄,從而鎖定該值的區間;
  2. 普通索引的鎖也是加載該索引上的,如果涉及到存在的記錄,會對該主鍵加行鎖;
  3. 普通索引的范圍查詢,同樣出現 next-key 查詢下一個區間的 bug。

普通字段

普通字段查詢,會查詢全表,這里鎖的話就會鎖住主鍵的所有區間。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM