Дедлок MySQL в модуле Sale: корзина и связанные товары
Откуда берётся deadlock в интернет-магазине
В MySQL InnoDB дедлок — это не «ошибка логики запроса», а фиксация цикла ожиданий блокировок между транзакциями. Пока клиенты оформляют заказы, фоновые задачи пересчитывают скидки или статистику покупок вместе с корзиной (b_sale_basket), несколько сессий могут одновременно трогать одни и те же агрегирующие строки. Если порядок захвата строк отличается, СУБД выбирает одну из транзакций как «жертву» и откатывает её с сообщением о deadlock.
Что за таблицы в цепочке
b_sale_basket хранит позиции корзины и привязку к заказу. Таблица b_sale_product2product обычно используется для учёта совместных покупок (связь «товар — сопутствующий») и накопительных счётчиков вроде CNT. Массовый UPDATE, который соединяет корзину с самой собой и одновременно обновляет счётчики по парам PRODUCT_ID / PARENT_PRODUCT_ID, легко создаёт широкий набор затронутых строк и долгие блокировки.
Фрагмент реального лога
Ниже — сокращённый вывод из трассировки InnoDB: две транзакции выполняют одинаковый по структуре запрос, но с разными ORDER_ID. Именно пересечение по строкам b_sale_product2product при разном порядке их захвата и приводит к взаимной блокировке.
*** (1) TRANSACTION:
UPDATE b_sale_product2product p2p, b_sale_basket b, b_sale_basket b1
SET p2p.CNT = p2p.CNT + 1
WHERE b.ORDER_ID = b1.ORDER_ID
AND b.ID <> b1.ID
AND b.ORDER_ID = 33989
AND p2p.PRODUCT_ID = b.PRODUCT_ID
AND p2p.PARENT_PRODUCT_ID = b1.PRODUCT_ID;
*** (2) TRANSACTION:
UPDATE b_sale_product2product p2p, b_sale_basket b, b_sale_basket b1
SET p2p.CNT = p2p.CNT + 1
WHERE b.ORDER_ID = b1.ORDER_ID
AND b.ID <> b1.ID
AND b.ORDER_ID = 33990
AND p2p.PRODUCT_ID = b.PRODUCT_ID
AND p2p.PARENT_PRODUCT_ID = b1.PRODUCT_ID;Как действовать после инцидента
- Снимите полный дамп статуса движка для конкретного момента: в рабочей среде это делают через стандартные средства мониторинга InnoDB и журналы ошибок MySQL — по ним видно последовательность ожиданий и индексы, по которым навешивались блокировки.
- Проверьте, нет ли дублирующихся агентов или параллельного запуска одного и того же пересчёта для пересекающихся заказов; иногда достаточно сериализовать блок обновления статистики по ключу склада или витрины.
- Убедитесь, что запрос использует предсказуемый доступ к строкам (одинаковый
ORDER BYвнутри критической секции, индексы под реальные условияWHERE), чтобы снизить вероятность «перекрёстного» порядка блокировок. - На уровне приложения допустимы повтор запроса после ответа о deadlock и снижение длины транзакций: не держите открытую транзакцию на время внешних HTTP-вызовов и тяжёлых циклов.
Итог
Такие дедлоки — сигнал, что конкурирующие потоки массово обновляют связанные счётчики одной и той же таблицы. Разбор лога показывает конкретные идентификаторы заказов и текст запроса; дальше работа сводится к уменьшению пересечения транзакций и выравниванию порядка доступа к строкам, а не к «отключению» проверок со стороны СУБД.
Не хотите копаться сами?
Починю за 1-3 дня. Без предоплаты — оплата по результату.
15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии