Начало работы с анализом проблем взаимоблокировки MySQL из исходного кода

задняя часть MySQL

В этой статье в основном рассказывается о том, как отладить исходный код MySQL, чтобы узнать, какие блокировки SQL действительно возьмет, чтобы перестать ловить креветок, угадывать или не знать, как поступать со сценариями, которые Бог Хэ Дэнчэн не написал.

После многих сложных одноэтапных отладок посреди ночи я наконец нашел идеальную точку останова и могу видеть большую часть процесса получения блокировок.

код находится вlock0lock.cизstatic enum db_err lock_rec_lock()В функции эта функция будет отображать процесс получения блокировки и успешность получения блокировки.

Для содержания предыдущего блога He Dengcheng (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 (блокировка записи без пробелов и блокировка X)

Процесс выглядит следующим образом

Вывод: чтобы удалить данные в соответствии с идентификатором первичного ключа, а другого индекса нет, этому SQL нужно только добавить блокировку X к индексу первичного ключа на записи с идентификатором = 10.

Сценарий 2: Удаление по уникальному индексу

Структура таблицы была доработана, добавлен уникальный индекс для имени

构造数据
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"

Посмотрите на результаты фактической отладки исходного кода первый шаг:

Шаг 2:
Вывод: этот процесс состоит в том, чтобы сначала добавить блокировку X к уникальному ключу uk_name, а затем добавить блокировку X к кластеризованному индексу (индексу первичного ключа).

Процесс выглядит следующим образом

Сценарий 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, а остальные 3 по одному ставиться не будут

Вывод: При обновлении без прохождения индекса sql пойдет聚簇索引(индекс первичного ключа) сканирует всю таблицу, поэтому каждая запись, независимо от того, соответствует ли она условиям, будет заблокирована с помощью X. Это еще не конец... Однако ради эффективности MySQL был оптимизирован.Для записей, которые не соответствуют условиям, блокировка будет снята после вынесения решения.Последнее удержание - это блокировка записи, которая соответствует условию, но блокировка/освобождение для запись, не удовлетворяющая условию, будет задержана, блокировка не будет пропущена.

Процесс выглядит следующим образом