14.7.5.3 Способы минимизации и обработки тупиков
Этот раздел опирается на концептуальную информацию о тупиках в разделе 14.7.5.2 «Обнаружение тупиков». Он объясняет, как организовать операции базы данных для минимизации тупиков и последующей обработки ошибок в приложениях.
Тупики — классическая проблема транзакционных баз данных, но они не опасны, если не возникают так часто, что определённые транзакции вообще нельзя выполнить. Обычно необходимо написать свои приложения так, чтобы они всегда были готовы повторно выполнить транзакцию, если она была отменена из-за тупика.
InnoDB использует автоматическое блокирование на уровне строк. Тупики могут возникнуть даже в случае транзакций, которые просто вставляют или удаляют одну строку. Это потому, что эти операции не являются по-настоящему “атомными”; они автоматически устанавливают блокировки на (возможно, нескольких) записях индекса строки, вставленной или удалённой.
Вы можете справиться с тупиками и уменьшить вероятность их возникновения с помощью следующих методов:
В любое время выполните
SHOW ENGINE INNODB STATUS, чтобы определить причину последнего тупика. Это поможет вам настроить ваше приложение, чтобы избежать тупиков.Если частые предупреждения о тупиках вызывают беспокойство, соберите более подробную информацию об отладке, включив переменную
innodb_print_all_deadlocks. Информация о каждом тупике, а не только о последнем, записывается в MySQL. Отключите этот параметр после завершения отладки.Всегда будьте готовы повторно выполнить транзакцию, если она завершится неудачно из-за тупика. Тупики не опасны. Просто попробуйте ещё раз.
Держите транзакции небольшими и кратковременными, чтобы они были менее подвержены конфликтам.
Выполняйте фиксацию транзакций сразу после внесения набора связанных изменений, чтобы уменьшить вероятность конфликтов. В частности, не оставляйте открытой интерактивную сессию mysql длительное время с незафиксированной транзакцией.
Если вы используете (
SELECT ... FOR UPDATEилиSELECT ... LOCK IN SHARE MODE), попробуйте использовать более низкий уровень изоляции, например,READ COMMITTED.При модификации нескольких таблиц в рамках одной транзакции или различных наборов строк в одной таблице выполняйте эти операции в согласованном порядке каждый раз. Тогда транзакции образуют чёткие очереди и не станут причиной тупиков. Например, организуйте операции базы данных в виде функций в вашем приложении или вызывайте хранимые процедуры, а не программируйте несколько похожих последовательностей
INSERT,UPDATEиDELETEоператоров в разных местах.Добавьте хорошо выбранные индексы в ваши таблицы, чтобы ваши запросы сканировали меньше записей индекса и устанавливали меньше блокировок. Используйте
EXPLAIN SELECT, чтобы определить, какие индексы сервер MySQL считает наиболее подходящими для ваших запросов.Используйте меньше блокировок. Если вы можете позволить себе разрешить
SELECTвозвращать данные из старой копии, не добавляйте к нему клаузуFOR UPDATEилиLOCK IN SHARE MODE. Использование уровня изоляцииREAD COMMITTEDздесь хорошо, потому что каждый согласованный считываемый в рамках одной транзакции считывает данные из своей свежей копии.-
Если ничего не помогает, сериализуйте свои транзакции с помощью блокировок на уровне таблицы. Правильный способ использования
LOCK TABLESс транзакционными таблицами, такими какInnoDBтаблицы, заключается в начале транзакции сSET autocommit = 0(а неSTART TRANSACTION), за которым следуетLOCK TABLES, и не вызыватьUNLOCK TABLESдо явной фиксации транзакции. Например, если вам нужно записать в таблицуt1и прочитать из таблицыt2, вы можете сделать это так:SET autocommit=0; LOCK TABLES t1 WRITE, t2 READ, ...;
... do something with tables t1 and t2 here ...COMMIT; UNLOCK TABLES;Блокировки на уровне таблиц предотвращают одновременные обновления таблицы, избегая тупиков за счёт меньшей отзывчивости для загруженного системы.
Другой способ сериализации транзакций — создание вспомогательной таблицы «семафор», которая содержит только одну строку. Пусть каждая транзакция обновляет эту строку перед доступом к другим таблицам. Таким образом, все транзакции происходят в последовательном порядке. Обратите внимание, что алгоритм обнаружения мгновенных тупиков
InnoDBтакже работает в этом случае, потому что сериализующая блокировка — это блокировка на уровне строк. При блокировках на уровне таблицы MySQL для разрешения тупиков необходимо использовать метод таймаута.
© 2025 Oracle
Licensed under the GPLv2 License.