Получение «Превышено время ожидания блокировки; попробуйте перезапустить транзакцию », хотя я не использую транзакцию

188

Я запускаю следующий оператор MySQL UPDATE:

mysql> update customer set account_import_id = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

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

В таблице содержится 406,733 строк.

Теги:
timeout

15 ответов

162
Лучший ответ

Вы используете транзакцию; autocommit не отключает транзакции, он просто заставляет их автоматически фиксировать в конце инструкции.

Что происходит, в какой-то другой поток есть фиксация записи на какой-либо записи (вы обновляете каждую запись в таблице!) Слишком долго, и ваш поток истекает.

Вы можете увидеть более подробную информацию о мероприятии, выпустив

SHOW ENGINE INNODB STATUS

после события (в редакторе sql). В идеале это делается на тихой тестовой машине.

  • 0
    Есть ли способ сохранить вывод в файл? Я попытался ПОКАЗАТЬ СТАТУС ДВИГАТЕЛЯ INNODB \ G> innodb_stat.txt, но не работает.
  • 13
    Из командной строки: mysql [вставить учетные данные] -e "ПОКАЗАТЬ СТАТУС ДВИГАТЕЛЯ INNODB \ G"> innodb_stat.txt
Показать ещё 4 комментария
244

КАК ОТКРЫТЬ UNLOCK для заблокированных таблиц в MySQL:

Ломающиеся блокировки, подобные этому, могут вызывать atomicity в базе данных, чтобы не выполняться в операторах sql, вызвавших блокировку.

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

1) Введите MySQL

mysql -u your_user -p

2) Посмотрите список заблокированных таблиц

mysql> show open tables where in_use>0;

3) Посмотрите список текущих процессов, один из которых заблокирует вашу таблицу (ы)

mysql> show processlist;

4) Убейте один из этих процессов

mysql> kill <put_process_id_here>;
  • 2
    Этот метод помогает мне снять блокировку без привилегии PROCESS.
  • 11
    Это опасно и взломано. Правильное решение - исправить ваше приложение.
Показать ещё 8 комментариев
75
mysql> set innodb_lock_wait_timeout=100

Query OK, 0 rows affected (0.02 sec)

mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 100   |
+--------------------------+-------+

Теперь снова запустите блокировку. У вас есть 100 секунд времени, чтобы отправить SHOW ENGINE INNODB STATUS\G в базу данных и посмотреть, какая другая транзакция блокирует ваши.

  • 6
    Этот ответ не объясняет, почему спрашивающий получает свою ошибку. Не могли бы вы уточнить, почему помимо того, чтобы просто дать ответ?
  • 5
    Что это за ответ?
Показать ещё 2 комментария
57

Посмотрите, настроена ли ваша база данных. Особенно изоляция транзакций. Не рекомендуется добавлять переменную innodb_lock_wait_timeout.

Проверьте уровень изоляции транзакции базы данных в mysql cli:

mysql> SELECT @@GLOBAL.tx_isolation, @@tx_isolation, @@session.tx_isolation;
+-----------------------+-----------------+------------------------+
| @@GLOBAL.tx_isolation | @@tx_isolation  | @@session.tx_isolation |
+-----------------------+-----------------+------------------------+
| REPEATABLE-READ       | REPEATABLE-READ | REPEATABLE-READ        |
+-----------------------+-----------------+------------------------+
1 row in set (0.00 sec)

Вы можете получить улучшения, изменяющие уровень изоляции, используйте оракул, например, READ COMMITTED вместо REPEATABLE READ (значения InnoDB по умолчанию)

mysql> SET tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> 

Также попробуйте использовать SELECT FOR UPDATE только в случае необходимости.

  • 1
    Это отличное решение для проблем блокировки.
  • 0
    К вашему сведению - dev.mysql.com/doc/refman/5.6/en/set-transaction.html
Показать ещё 1 комментарий
12

Ни один из предлагаемых решений не работал у меня, но это делалось.

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

SHOW PROCESSLIST;

После обнаружения процесса блокировки найдите id и запустите:

KILL {id};

Повторно запустите свой первоначальный запрос.

  • 0
    Я случайно УБил все процессы, перечисленные в SHOW PROCESSLIST; Теперь я получаю 500 ошибок в phpmyadmin. Эта ошибка 500 связана с убийством этих процессов? Если да, как я могу перезапустить его.
12

100% с тем, что сказал MarkR. autocommit делает каждый оператор транзакцией одного оператора.

SHOW ENGINE INNODB STATUS должен дать вам некоторые подсказки относительно причины взаимоблокировки. Посмотрите также на свой журнал медленных запросов, чтобы узнать, что еще запрашивает таблица, и попытайтесь удалить все, что делает полную таблицу. Блокировка уровня строки работает хорошо, но не тогда, когда вы пытаетесь заблокировать все строки!

5

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

  • 3
    может быть, innodb_lock_wait_timeout в my.cnf
  • 0
    да, так и должно быть.
Показать ещё 1 комментарий
1

Число строк не огромно... Создайте индекс в account_import_id, если это не первичный ключ.

CREATE INDEX idx_customer_account_import_id ON customer (account_import_id);
  • 0
    OMG ... это только спасло меня. Я по-королевски прикрутил производственную БД, опустив индекс, и это исправило это. Спасибо вам.
1

Убедитесь, что в таблицах базы данных используется механизм хранения InnoDB и уровень изоляции транзакций READ-COMMITTED.

Вы можете проверить это с помощью SELECT @@GLOBAL.tx_isolation, @@tx_isolation; на консоли mysql.

Если он не установлен для READ-COMMITTED, вы должны установить его. Перед установкой убедитесь, что у вас есть привилегии SUPER в mysql.

Вы можете получить помощь http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html.

Установив это, я думаю, ваша проблема будет решена.


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

0

Если вы только что убили большой запрос, rollback займет время. Если вы выполните другой запрос до того, как завершенный откат будет завершен, вы можете получить ошибку тайм-аута блокировки. Это то, что случилось со мной. Решение было просто немного подождать.

Подробности:

Я выполнил запрос DELETE, чтобы удалить около 900 000 из примерно 1 миллиона строк.

Я запустил это по ошибке (удаляет только 10% строк): DELETE FROM table WHERE MOD(id,10) = 0

Вместо этого (удаляет 90% строк): DELETE FROM table WHERE MOD(id,10) != 0

Я хотел удалить 90% строк, а не 10%. Поэтому я убил процесс в командной строке MySQL, зная, что он откатит все удаленные строки.

Затем я немедленно выполнил правильную команду и вскоре после этого получил ошибку lock timeout exceeded времени lock timeout exceeded. Я понял, что блокировка может быть rollback убитого запроса, все еще происходящего в фоновом режиме. Поэтому я подождал несколько секунд и снова запустил запрос.

0

В моем случае я выполнял ненормальный запрос для исправления данных. Если вы заблокируете таблицы в своем запросе, вам не придется иметь дело с таймаутом блокировки:

LOCK TABLES 'customer' WRITE;
update customer set account_import_id = 1;
UNLOCK TABLES;

Это, вероятно, не очень хорошая идея для нормального использования.

Для получения дополнительной информации см.: Справочное руководство по MySQL 8.0

0

Такое происходило со мной, когда я использовал php выход языковой конструкции; в середине транзакции. Тогда это транзакция "зависает", и вам нужно убить процесс mysql (описанный выше с помощью processlist;)

0

Поздно к вечеринке (как обычно), однако моя проблема заключалась в том, что я написал плохой SQL (будучи новичком), а несколько процессов имели блокировку записи (ов) < - не уверены в соответствующей формулировке. Мне пришлось просто: SHOW PROCESSLIST, а затем убить идентификаторы, используя KILL <id>

-2

Если у вас больше ничего не работает и его собственный экземпляр, я считаю, что было бы более эффективно просто перезапустить mysql

-3

Имела ту же ошибку, хотя я только обновлял одну таблицу с одной записью, но после перезапуска mysql она была разрешена.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню