從源碼分析 MySQL 死鎖問題入門

這篇文章主要講的是如何經過調試 MySQL 源碼,知道一條 SQL 真正會拿哪些鎖,再也不抓蝦,瞎猜或者何登成大神沒寫過的場景就不知道如何處理了sql

經過好多個深夜艱難的單步調試,終於找到了一個理想的斷點,能夠看到大部分獲取鎖的過程bash

代碼在lock0lock.cstatic enum db_err lock_rec_lock() 函數中,這個函數會顯示,獲取鎖的過程,以及獲取鎖成功與否的狀況函數

對於以前何登成大神博客裏面的內容(hedengcheng.com/?p=771), 咱們來作實驗逐個驗證(如下介紹的都是在 RC 隔離級別下的實驗)測試

場景1:經過主鍵進行刪除

表結構優化

CREATE TABLE `t1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

delete from t1 where id = 10;
複製代碼

能夠看到,對索引 PRIMARY 加鎖,mode = 1027,1027是什麼意思呢?1027 = LOCK_REC_NOT_GAP + LOCK_X(非 gap 的記錄鎖且是 X 鎖)ui

過程以下 spa

結論:根據主鍵 id 去刪除數據,且沒有其它索引的狀況下,此 SQL 只須要在 id = 10 這條記錄上對主鍵索引加 X 鎖便可

場景2:經過惟一索引進行刪除

表結構作了微調,增長了 name 的惟一索引3d

構造數據
CREATE TABLE `t2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_name` (`name`)
) ;
INSERT INTO `t2` (`id`, `name`) VALUES 
	(1,'M'),
	(2,'Y'),
	(3,'S'),
	(4,'Q'),
	(5,'L');
	
測試sql語句
delete from t2 where name = "Y"
複製代碼

來看實際源碼調試的結果 第一步: 調試

第二步:
結論:這個過程是先對惟一鍵 uk_name 加 X 鎖,而後再對聚簇索引(主鍵索引)加 X 鎖

過程以下 code

場景3:經過普通索引進行刪除

構造數據
CREATE TABLE `t3` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`) 
);
INSERT INTO `t3` (`id`, `name`) VALUES 
	(1,'N'),
	(2,'G'),
	(3,'I'),
	(4,'N'),
	(5,'X');
	
測試語句:
delete from t3 where name = "N";
複製代碼

調試過程如圖:

結論:經過普通索引進行更新時,會對知足條件的全部普通索引加 X 鎖,同時會對相關的主鍵索引加 X 鎖

過程以下

場景4:不走索引進行刪除

CREATE TABLE `t4` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
)

INSERT INTO `t4` (`id`, `name`) VALUES 
	(1,'M'),
	(2,'Y'),
	(3,'S'),
	(4,'Q'),
	(5,'L');
	
delete from t4 where name = "S";
複製代碼

總共有 5 把 X 鎖,剩下的 3 把就不一一放上來了

結論:不走索引進行更新時,sql 會走聚簇索引(主鍵索引)對全表進行掃描,所以每條記錄,不管是否知足條件,都會被加上X鎖。還沒完... 可是爲了效率考量,MySQL作了優化,對於不知足條件的記錄,會在判斷後放鎖,最終持有的,是知足條件的記錄上的鎖,可是不知足條件的記錄上的加鎖/放鎖動做不會省略。

過程以下

相關文章
相關標籤/搜索