Работа вокруг ошибочной мертвой блокировки “MySQL нашла при попытке получить блокировку; попытайтесь перезапустить транзакцию”

У меня есть таблица MySQL приблизительно с 5 000 000 строк, которые постоянно обновляются маленькими способами параллельными процессами Perl, соединяющимися через DBI. Таблица имеет приблизительно 10 столбцов и несколько индексов.

Одна довольно общая операция иногда дает начало следующей ошибке:

DBD::mysql::st execute failed: Deadlock found when trying to get lock; try restarting transaction at Db.pm line 276.

SQL-оператор, который инициировал ошибку, является чем-то вроде этого:

UPDATE file_table SET a_lock = 'process-1234' WHERE param1 = 'X' AND param2 = 'Y' AND param3 = 'Z' LIMIT 47

Ошибка инициирована только иногда. Я оценил бы в 1% вызовов или меньше. Однако это никогда не происходило с маленькой таблицей и больше стало распространено, поскольку база данных выросла.

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

Я не сделал большой настройки на MySQL или DBD:: mysql. MySQL является стандартным развертыванием Соляриса, и соединение с базой данных настраивается следующим образом:

my $dsn = "DBI:mysql:database=" . $DbConfig::database . ";host=${DbConfig::hostname};port=${DbConfig::port}";
my $dbh = DBI->connect($dsn, $DbConfig::username, $DbConfig::password, { RaiseError => 1, AutoCommit => 1 }) or die $DBI::errstr;

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

У меня есть два вопроса:

  1. Что точно о моей ситуации вызывает ошибку выше?

  2. Существует ли простой способ работать вокруг этого или уменьшить его частоту? Например, как точно я иду о "перезапуске транзакции в строке Db.pm 276"?

Заранее спасибо.

29
задан Anon Gordon 7 April 2010 в 21:16
поделиться

1 ответ

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

Единственный способ справиться с тупиками - это написать код, который их ожидает. Обычно это не очень сложно, если код вашей базы данных хорошо написан. Часто можно просто использовать try / catch вокруг логики выполнения запроса и искать взаимоблокировку при возникновении ошибок. Если вы поймаете один из них, обычное дело - просто попытаться снова выполнить неудавшийся запрос.

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

72
ответ дан 28 November 2019 в 00:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: