До основного вмісту

Дедлоки 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.
← Назад до бази знань Поставити питання підтримці