Как исправить эту проблему взаимоблокировки MySQL/Innodb в неблокирующей среде?

Мы используем MySQL с хранилищем Innodb Engine. У нас есть среда с событиями, которая отправляет несколько одновременных запросов к таблице. В основном это работает следующим образом: у нас есть функция find_or_insert, которая делает следующее: - find() -> по результату, если пусто -> вставить -> по результату find()

Мы используем неблокирующий драйвер MySQL, поэтому, по сути, когда мы запускаем этот небольшой алгоритм более одного раза одновременно, он запускает все находки перед вставкой первого результата... и т. д.

К сожалению, мы получаем эти ошибки: "Обнаружена взаимоблокировка при попытке получить блокировку; попробуйте перезапустить транзакцию"

Кто-нибудь может помочь с этим?

[EDIT]: Кроме того, я на самом деле не понимаю, почему MySQL нужно блокировать таблицу только для того, чтобы вставить сюда новый элемент. Первоначально я думал, что виновником здесь был автоинкремент, поэтому я удалил его ... но я все еще получаю сообщение об ошибке. Есть ли способ запретить MySQL блокировать таблицу при вставках?


person Julien Genestoux    schedule 15.05.2009    source источник
comment
Сначала попробуйте найти полезное название для этого вопроса.   -  person VVS    schedule 15.05.2009
comment
Ой! Хорошо, я поменяю это на что-то более значимое.   -  person Julien Genestoux    schedule 15.05.2009


Ответы (3)


Воспользуйтесь справочным руководством по mysql для диагностики и устранения проблемы. Похоже, вы делаете кеш. Вероятной причиной может быть то, что многие клиенты одновременно обращаются к таблице, пытаясь создать «первую версию» (т.е. нажимают «если пустая вставка»). Может быть, вы могли бы добавить псевдослучайную задержку или скоординировать создателей, чтобы у вас не было много одновременных вызовов создания в БД?

РЕДАКТИРОВАТЬ: Вы видели эту страницу? Похоже, вам нужно установить параметр my.cnf, чтобы отключить блокировки для каждой таблицы с помощью innodb. Однако я в основном предполагал, что ваш тест может быть непредставим, поскольку он может содержать гораздо более высокий процент писателей, чем в реальной ситуации. Если вы запустите 100 потоков с пустой таблицей, все они мгновенно заблокируются при создании (возможно, даже для одного и того же значения). Это намного хуже, чем в средней ситуации, когда у вас лучше разброс по ключам, меньше промахов и намного выше процент прочтений. Если это ожидаемое поведение (т. е. у вас будет такое поведение в реальном времени), я бы предложил добавить стратегию отсрочки в операторы создания.

person Alexander Torstling    schedule 15.05.2009
comment
технически это не кеш, но механизм аналогичен... однако в моем случае все запросы извлекают/вставляют другую строку... - person Julien Genestoux; 15.05.2009
comment
Я отредактировал ответ, чтобы отразить ваши изменения и комментарий, который вы оставили Карлу. Вы видите блокировки таблиц или у вас есть несколько вставок в одной строке? - person Alexander Torstling; 16.05.2009

Вам нужно, чтобы эти запросы выполнялись по одному, поэтому, возможно, перестаньте использовать этот неблокирующий драйвер. Или реализовать свой собственный механизм блокировки. Дождитесь окончания одного, прежде чем переходить к следующему.

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

person Karl    schedule 15.05.2009
comment
Я не могу использовать блокирующий драйвер, потому что нам нужна молниеносная скорость... Приложение на самом деле представляет собой приложение XMPP, которому нужно обрабатывать тысячи подключений в секунду, и большинство из них даже не будут касаться базы данных... так что мы можем' действительно блокировать всех только из-за базы данных. - person Julien Genestoux; 15.05.2009

Я меняю свой ответ, чтобы отразить, что вопрос пересмотрен. Теперь похоже, что это проблема только с одновременными вставками, а не зависимость от поведения поиска.

Насколько я понимаю, InnoDB блокирует строки при вставках, и вы не можете отключить это. Однако вы [edit] не можете использовать INSERT DELAYED. Я только что прочитал, что это недоступно в InnoDB.

http://dev.mysql.com/doc/refman/5.0/en/insert-delayed.html

Возможно, явная LOCK TABLES вокруг всех ваших коллективных записей переопределит поведение блокировки по умолчанию. Если в течение интервала, когда происходят события записи, в таблице нет других операций, это может сработать.

http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html

person Walt Jones    schedule 15.05.2009