Получение тупиков в MySQL - PullRequest
1 голос
/ 27 мая 2010

Мы очень расстраиваемся из-за тупиковых ситуаций в MySQL. Это не из-за превышения времени ожидания блокировки, так как взаимные блокировки возникают мгновенно, когда они случаются. Вот код SQL, который выполняется в 2-х отдельных потоках (с 2-мя отдельными подключениями из пула соединений), что вызывает взаимоблокировку:

UPDATE Sequences SET Counter = LAST_INSERT_ID(Counter + 1) WHERE Sequence IS NULL

Таблица последовательностей имеет 2 столбца: последовательность и счетчик

LAST_INSERT_ID позволяет нам получить это обновленное значение счетчика в соответствии с рекомендацией MySQL . Это прекрасно работает для нас, но мы получаем эти тупики! Почему мы их получаем и как мы можем их избежать ??

Большое спасибо за любую помощь в этом.

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

Ответы [ 3 ]

2 голосов
/ 27 мая 2010

Оберните ваши sql заявления в транзакции. Если вы не используете транзакцию, вы получите условие гонки на LAST_INSERT_ID.

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

Ваше третье решение - использовать LOCK_TABLES , чтобы заблокировать таблицу последовательности, чтобы никакой другой процесс не мог получить к ней доступ одновременно. Это, вероятно, самое медленное решение, если вы не используете INNODB.

0 голосов
/ 27 мая 2010

Никакой другой SQL не задействован? Мне кажется это немного маловероятным.

'where sequence is null', вероятно, вызывает полное сканирование таблицы, вызывая блокировку чтения для каждой строки / страницы / ....

Это становится проблемой, если (ваш конкретный движок не использует MVCC и) была INSERT, которая предшествовала вашему обновлению в рамках той же транзакции. Этот INSERT получил бы эксклюзивную блокировку для какого-либо ресурса (row / page / ...), что приведет к ожиданию получения блокировки чтения любым другим потоком. Таким образом, два подключения могут сначала выполнить вставку, в результате чего каждое из них будет иметь монопольную блокировку для некоторой небольшой части таблицы, а затем они оба попытаются выполнить ваше обновление, требуя, чтобы каждое из них могло установить блокировку чтения вся таблица.

0 голосов
/ 27 мая 2010

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

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

Во-вторых, если все, что вы делаете - это обновляете счетчик, вам действительно нужно использовать столбец AUTO_INCREMENT для Counter вместо того, чтобы полагаться на процесс «выбрать и обновить», который, как вы видели, состояние гонки, которое может привести к тупикам. По сути, свойство AUTO_INCREMENT вашего столбца таблицы будет действовать как счетчик для вас.

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

Ваше лучшее решение - выяснить, как это сделать без транзакции, и AUTO_INCREMENT позволит вам сделать это.

...