#php #mysql #deadlock
#php #mysql #взаимоблокировка
Вопрос:
Я не могу понять, какой запрос вызывает Deadlock found when trying to get lock; try restarting transaction
. Моя оболочка для mysql имеет следующие строки
if (mysql_errno($this->conn) == 1213) {
$this->bug_log(0,"Deadlock. SQL:".$this->sql);
}
где bug_log
выполняется запись в файл.
Файл журнала ошибок не содержит ошибок взаимоблокировки, но /var/log/mysqld.log
содержит несколько записей:
111016 3:00:02 [ERROR] /usr/libexec/mysqld: Deadlock found when trying to get lock; try restarting transaction
111016 3:00:02 [ERROR] /usr/libexec/mysqld: Sort aborted
111016 3:00:02 [ERROR] /usr/libexec/mysqld: Deadlock found when trying to get lock; try restarting transaction
111016 3:00:02 [ERROR] /usr/libexec/mysqld: Sort aborted
111016 3:00:02 [ERROR] /usr/libexec/mysqld: Deadlock found when trying to get lock; try restarting transaction
111016 3:00:02 [ERROR] /usr/libexec/mysqld: Sort aborted
Как я могу отследить это?
Ответ №1:
Обновление с предложением WHERE, которое не является уникальным столбцом, приведет к взаимоблокировке, если другая транзакция ожидает завершения текущей транзакции. Вот быстрый тест:
CREATE TABLE test (pk int PRIMARY KEY, a int);
INSERT INTO test VALUES (0, 0);
INSERT INTO test VALUES (1, 0);
Сеанс 1
BEGIN;
SELECT a FROM test WHERE pk=0 FOR UPDATE;
Сессия 2
BEGIN;
SELECT a FROM test WHERE pk=0 FOR UPDATE;
(Сеанс 2 теперь заблокирован)
Сеанс 1
UPDATE test SET a=1 WHERE a>0;
В сеансе 2 мы получаем сообщение об ошибке
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
Если в предложении WHERE обновления мы используем только столбец pk, ошибка не возникает.
Комментарии:
1. Что значит «использовать только столбец pk»? Это то, что вы делаете в своем примере, не так ли?
2. нет — в предложении WHERE обновления у меня есть «a> 0». Если я напишу там «pk = 0» (или что-нибудь, что использует только уникальные столбцы), я не получу сообщение об ошибке.
3. Я думаю, что это первый раз, когда я действительно понял взаимоблокировки против простых блоков.
Ответ №2:
Я видел, как это происходило при одном или нескольких из следующих условий:
- Объединение одной и той же таблицы несколько раз в запросе (САМОСОЕДИНЕНИЕ)
- При использовании транзакций, содержащих запросы, которые одновременно обрабатывают одну и ту же таблицу несколькими способами
- При использовании транзакций и использовании той же таблицы, что и САМОСОЕДИНЕНИЕ или подзапрос
Это может быть трудно отследить, но ситуация в основном говорит о том, что один запрос препятствует запуску другого, что, в свою очередь, препятствует завершению первого и т.д…
Комментарии:
1. У меня есть вложенный запрос, но не для self. Как может быть, что это вызывает взаимоблокировку каждый раз?
2. Вы используете транзакции? Это также может привести к тому, что две транзакции работают с одной и той же таблицей, но с разными ключевыми словами. Например
UPDATE TABLE ... WHERE group_id=X AND user_id=Y
, иUPDATE TABLE ... WHERE user_id=Y AND group_id=X
предполагая, что это разные ключи. Вы можете видеть, что если бы они выполнялись одновременно, они заблокировали бы другой индекс для возврата другого запроса, что привело бы к взаимоблокировке. Я бы проверил ваши запросы и убедился, что они записаны в том же порядке при работе с любыми ИНДЕКСАМИ.3. может быть, но как мне найти другой запрос? В настоящее время я отслеживал этот запрос на предмет взаимоблокировки:
UPDATE players SET chatban = chatban - 1 WHERE recent=1 and chatban > 0
как это может быть?4. Найдите все остальные запросы с помощью проигрывателей и сравните запросы. Возможно, вы выбираете тот, ГДЕ chatban> 0 И recent= 1, что может вызвать это.