В моем приложении время от времени возникают два запроса (из разных процессов), которые вызывают тупик.
Запрос № 1
UPDATE tblA, tblB SET tblA.varcharfield=tblB.varcharfield WHERE tblA.varcharfield IS NULL AND [a few other conditions];
Запрос № 2
INSERT INTO tmp_tbl SELECT * FROM tblA WHERE [various conditions];
Оба эти запроса занимают значительное время, поскольку в этих таблицах миллионы строк. Когда выполняется запрос № 2, кажется, что tblA
заблокирован в режиме S
. Похоже, что запрос № 1 требует блокировки X
. Поскольку это несовместимо с блокировкой S
, запрос № 1 ожидает до 30 секунд, после чего я захожу в тупик:
Ошибка сериализации: 1213 Обнаружен тупик при попытке получить блокировку; попробуйте перезапустить транзакцию
Исходя из того, что я прочитал в документации , я думаю, у меня есть пара вариантов:
- Установить индекс для tblA.varcharfield. К сожалению, я думаю, что для этого потребуется очень большой индекс для хранения поля varchar (512). (см. Правку ниже ... это не сработало.)
- Отключить блокировку с помощью
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
. Я не понимаю последствий этого и беспокоюсь о поврежденных данных. В настоящее время я не использую явные транзакции в своем приложении, но, возможно, когда-нибудь в будущем.
- Разделите мои трудоемкие запросы на маленькие кусочки, чтобы они могли стоять в очереди и запускаться в MySQL без истечения 30-секундного времени ожидания. Это не решило бы суть проблемы, и я обеспокоен тем, что, когда мои серверы баз данных будут заняты, проблема возникнет снова.
- Просто повторять запросы снова и снова ... не вариант, на который я надеюсь.
Как мне поступить? Есть ли альтернативные методы, которые я должен рассмотреть?
РЕДАКТИРОВАТЬ: Я попытался установить индекс для varcharfield, но таблица по-прежнему блокируется. Я подозреваю, что блокировка происходит, когда часть UPDATE
фактически выполняется. Есть другие предложения, чтобы обойти эту проблему?