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

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

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

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

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

Ответ 1

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

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

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

SHOW ENGINE INNODB STATUS

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

Ответ 2

КАК ОТКРЫТЬ 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>;

Ответ 3

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 в базу данных и посмотреть, какая другая транзакция блокирует ваши.

Ответ 4

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

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

mysql> SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation, @@session.transaction_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 Defaults)

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 только в случае необходимости.

Ответ 5

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

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

SHOW PROCESSLIST;

Как только вы обнаружите процесс блокировки, найдите его id и запустите:

KILL {id};

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

Ответ 6

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

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

Ответ 7

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

Ответ 8

Убедитесь, что в таблицах базы данных используется механизм хранения 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) столкнулись с подобными сообщениями об ошибках в этом контексте, возможно, дважды проверьте, что...

Ответ 9

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

CREATE INDEX idx_customer_account_import_id ON customer (account_import_id);

Ответ 10

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

Ответ 11

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

Ответ 12

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

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

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

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

Ответ 13

Если вы только что убили большой запрос, 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 убитого запроса, все еще происходящего в фоновом режиме. Поэтому я подождал несколько секунд и снова запустил запрос.

Ответ 14

Я столкнулся с этим, имея 2 соединения с Doctrine DBAL, одно из которых не транзакционное (для важных журналов), они предназначены для параллельной работы, не зависящей друг от друга.

CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery()
)

Мои тесты интеграции были свернуты в транзакции для отката данных после самого теста.

beginTransaction()
CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery() // CONFLICT
)
rollBack()

Моим решением было отключить транзакцию обертывания в этих тестах и сбросить данные БД другим способом.

Ответ 15

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

Я отключил autocommit а затем он работал, просто добавив COMMIT в конце предложения SQL. Насколько я понял, это освобождает буфер по битам вместо ожидания в конце команды.

Чтобы соответствовать примеру OP, это должно сработать:

mysql> set autocommit=0;

mysql> update customer set account_import_id = 1; commit;

Не забудьте снова активировать autocommit если вы хотите оставить конфигурацию MySQL, как и раньше.

mysql> set autocommit=1;

Ответ 16

Размер моей базы данных сейчас почти 120 ГБ,
и я хочу удалить некоторые записи из одной из моей таблицы,
Когда я запускаю этот запрос

"DELETE FROM images ГДЕ imageDate <= '2018-11-02';

Я получаю ту же ошибку

"Код ошибки: 1205. Превышено время ожидания блокировки; попробуйте перезапустить транзакцию"

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

Ответ 17

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

Ответ 18

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