как избежать мертвой блокировки в 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')

Как я могу избежать мертвой блокировки? Существует ли способ измениться на запрос, чтобы заставить его работать, или я должен сделать что-то еще?

Ошибки всегда не происходит, конечно, только после выполнения этого запроса много времен и в нескольких потоках.

10
задан olamundo 18 March 2010 в 14:32
поделиться

2 ответа

Вероятно, вы получите лучшую производительность, если замените «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);
5
ответ дан 3 December 2019 в 21:21
поделиться

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

Каждый раз, когда вы вставляете / обновляете / или удаляете строку, устанавливается блокировка. Чтобы избежать взаимоблокировки, вы должны убедиться, что параллельные транзакции не обновляют строку в порядке, который может привести к взаимоблокировке. Вообще говоря, чтобы избежать взаимоблокировки , вы должны получать блокировку всегда в одном и том же порядке даже в разных транзакциях (например, всегда сначала таблица A, затем таблица B).

Но если в рамках одной транзакции вы вставляете только одну таблицу, это условие выполняется, и это обычно не должно приводить к тупиковой ситуации. Вы делаете что-то еще в транзакции?

Однако может возникнуть взаимоблокировка, если отсутствуют индексы . Когда строка вставлена ​​/ обновлена ​​/ удалена, базе данных необходимо проверить реляционные ограничения, то есть убедиться, что отношения согласованы. Для этого базе данных необходимо проверить внешние ключи в связанных таблицах. Это может привести к получению другой блокировки, кроме измененной строки. Убедитесь, что у внешних ключей всегда есть индекс (и, конечно, первичных ключей), иначе это может привести к блокировке таблицы вместо блокировки строки . Если происходит блокировка таблицы, конкуренция за блокировку выше и вероятность тупиковой ситуации увеличивается.

Не знаю, что именно происходит в вашем случае, но, возможно, это поможет.

12
ответ дан 3 December 2019 в 21:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: