К основному содержимому

Дедлоки InnoDB: диагностика блокировок и их устранение

MySQL / MariaDB · 29.09.2026

Что такое дедлок в InnoDB

Дедлок — это взаимная блокировка: транзакция A ждёт освобождения строки, занятой транзакцией B, а транзакция B в этот момент ждёт строку, занятую транзакцией A. Ни одна из них не может продолжить работу, и InnoDB через встроенный детектор сам обрывает одну из транзакций с ошибкой Deadlock found when trying to get lock. Это не сбой сервера, а штатный механизм защиты от зависания.

В отличие от обычной блокировки, которая просто заставляет транзакцию подождать, дедлок требует вмешательства приложения: код должен поймать ошибку и повторить транзакцию заново.

Разделяемые и монопольные блокировки строк

InnoDB блокирует не таблицу целиком, а отдельные строки и промежутки между ними. Понимание типов блокировок помогает читать вывод диагностики.

  • Shared lock (S) — разделяемая блокировка, ставится при SELECT ... FOR SHARE, разрешает другим транзакциям тоже читать строку.
  • Exclusive lock (X) — монопольная блокировка, ставится при UPDATE, DELETE и SELECT ... FOR UPDATE, запрещает любой доступ другим транзакциям.
  • Gap lock — блокировка промежутка между значениями индекса, нужна для предотвращения фантомных строк при повторяемом чтении.

Как найти последний дедлок на сервере

Информация о последнем зафиксированном дедлоке хранится в статусе движка InnoDB. Команда выводит обе транзакции, их блокировки и то, какую из них сервер откатил.

SHOW ENGINE INNODB STATUS\G

В блоке LATEST DETECTED DEADLOCK видно текст запроса каждой транзакции, список удерживаемых и ожидаемых блокировок, а в конце — строку WE ROLL BACK TRANSACTION с номером отменённой транзакции. Разбор плана этих запросов через EXPLAIN часто показывает, что оба запроса идут по разным индексам к одним и тем же строкам.

Таблица типовых причин дедлоков

ПричинаПримерЧто делать
Разный порядок блокировокТранзакция A обновляет строки 1→2, транзакция B — 2→1Зафиксировать единый порядок изменения строк
Долгая транзакцияОткрытая транзакция ждёт ответа внешнего сервисаНе держать транзакцию открытой во время сетевых вызовов
Отсутствие индексаUPDATE идёт по неиндексированному полюДобавить индекс, чтобы блокировался диапазон меньше

Частые причины дедлоков в реальных приложениях

На практике большинство дедлоков повторяются по одному и тому же сценарию.

  • Два обработчика заказа одновременно списывают остаток товара в разном порядке строк.
  • Триггер на таблице делает вставку в другую таблицу, создавая скрытую вторую блокировку.
  • Массовое обновление без сортировки строк по первичному ключу — порядок блокировок становится случайным.
  • Долгая транзакция удерживает блокировку, пока приложение ждёт ответа от очереди или внешнего API.

Как снизить число дедлоков

Полностью убрать дедлоки нельзя — это часть нормальной работы MySQL под нагрузкой, но их частоту снижают несколько приёмов.

-- Сортировка строк по первичному ключу перед изменением
SELECT id FROM orders WHERE status = 'new' ORDER BY id FOR UPDATE;
  • Обновлять строки в одном и том же порядке во всех местах кода.
  • Держать транзакции короткими: не выполнять внешние вызовы между BEGIN и COMMIT.
  • Добавлять индексы под условия WHERE в UPDATE и DELETE, чтобы блокировался только нужный диапазон.
  • Повторять транзакцию автоматически при ошибке 1213 (deadlock), обычно двух-трёх попыток достаточно.

Итог: чек-лист диагностики дедлоков

  • Прочитать LATEST DETECTED DEADLOCK в SHOW ENGINE INNODB STATUS.
  • Определить порядок блокировок в обеих транзакциях.
  • Проверить, есть ли подходящий индекс под условия запросов.
  • Сократить транзакцию до минимально необходимых операций.
  • Добавить в код повтор транзакции при ошибке 1213.
← Назад в базу знаний Задать вопрос поддержке