Как избежать тупика в mysql
У меня есть следующий запрос (все таблицы - innoDB)
INSERT INTO busy_machines(machine)
SELECT machine FROM all_machines
WHERE machine NOT IN (SELECT machine FROM busy_machines)
and machine_name!='Main'
LIMIT 1
Что вызывает тупик, когда я запускаю его в потоках, очевидно, из-за внутреннего выбора, правильно?
Ошибка, которую я получаю:
(1213, 'Deadlock found when trying to get lock; try restarting transaction')
Как я могу избежать тупика? Есть ли способ изменить запрос, чтобы заставить его работать, или мне нужно сделать что-то еще?
Ошибка не всегда, конечно, только после выполнения этого запроса много раз и в нескольких потоках.
Ответы
Ответ 1
Вероятно, вы получите лучшую производительность, если вы замените "NOT IN" внешним соединением.
Вы также можете разделить это на два запроса, чтобы избежать вставки и выбора одной и той же таблицы в одном запросе.
Что-то вроде этого:
SELECT a.machine
into @machine
FROM all_machines a
LEFT OUTER JOIN busy_machines b on b.machine = a.machine
WHERE a.machine_name!='Main'
and b.machine IS NULL
LIMIT 1;
INSERT INTO busy_machines(machine)
VALUES (@machine);
Ответ 2
Насколько я понимаю, выбор не вызывает блокировки и не должен быть причиной тупика.
Каждый раз, когда вы вставляете/обновляете/или удаляете строку, происходит блокировка. Чтобы избежать тупиковой ситуации, вы должны убедиться, что параллельные транзакции не обновляют строку в порядке, который может привести к тупиковой ситуации. Вообще говоря, чтобы избежать тупика , вы должны получать блокировку всегда в том же порядке даже в разных транзакциях (например, всегда сначала таблица A, а затем таблица B).
Но если внутри одной транзакции вы вставляете только одну таблицу, это условие выполняется, и это обычно не должно приводить к тупиковой ситуации. Вы делаете что-то еще в транзакции?
Однако возможен тупик, если есть отсутствующие индексы. Когда строка вставлена /обновлена /удалена, базе данных необходимо проверить реляционные ограничения, то есть убедиться, что отношения согласованы. Для этого база данных должна проверять внешние ключи в связанных таблицах. Это может привести к приобретению другой блокировки, чем измененная строка. Убедитесь, что всегда есть индекс для внешних ключей (и, конечно, первичных ключей), иначе это может привести к блокировке таблицы вместо блокировки строк . Если происходит блокировка таблицы, конфликт блокировки выше и вероятность блокировки увеличивается.
Не уверен, что происходит именно в вашем случае, но, возможно, это помогает.