Я получаю Deadlocks от блокировок на столе при частой вставке из нескольких источников. Вот краткий обзор моих процессов.
START TRANSACTION
UPDATE vehicle_image
SET active = 0
WHERE vehicleID = SOMEID AND active = 1
Loop:
INSERT INTO vehicle_image (vehicleID, vehicleImageFilePath, vehicleImageSplashFilePath
,vehicleImageThumbnailFilePath, vehicleImageMiniFilePath, mainVehicleImage, active)
VALUES (%s, %s, %s, %s, %s, %s, 1);
END TRANSACTION
Вывод SHOW Create table vehicle_image;
:
CREATE TABLE `vehicle_image` (
`vehicleImageID` int(11) NOT NULL AUTO_INCREMENT,
`vehicleID` int(11) DEFAULT NULL,
`vehicleImageFilePath` varchar(200) DEFAULT NULL,
`vehicleImageSplashFilePath` varchar(200) DEFAULT NULL,
`vehicleImageThumbnailFilePath` varchar(200) DEFAULT NULL,
`vehicleImageMiniFilePath` varchar(200) DEFAULT NULL,
`mainVehicleImage` bit(1) DEFAULT NULL,
`active` bit(1) DEFAULT b'1',
`userCreated` int(11) DEFAULT NULL,
`dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`userModified` int(11) DEFAULT NULL,
`dateModified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`vehicleImageID`),
KEY `active` (`active`),
KEY `mainvehicleimage` (`mainVehicleImage`),
KEY `vehicleid` (`vehicleID`)
) ENGINE=InnoDB AUTO_INCREMENT=22878102 DEFAULT CHARSET=latin1
И последний тупик, данный SHOW engine innodb status
:
LATEST DETECTED DEADLOCK
------------------------
2018-03-27 12:31:15 11a58
*** (1) TRANSACTION:
TRANSACTION 5897678083, ACTIVE 2 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1248, 2 row lock(s), undo log entries 1
MySQL thread id 873570, OS thread handle 0x124bc, query id 198983754 ec2-34-239-240-179.compute-1.amazonaws.com 34.239.240.179 image_processor update
INSERT INTO vehicle_image (vehicleID, vehicleImageFilePath, vehicleImageSplashFilePath, vehicleImageThumbnailFilePath, vehicleImageMiniFilePath, mainVehicleImage, active)
VALUES (70006176, 'f180928(1)1522168276.230837full.jpg', 'f180928(1)1522168276.230837splash.jpg', 'f180928(1)1522168276.230837thumb.jpg', 'f180928(1)1522168276.230837mini.jpg', 1, 1)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 875 page no 238326 n bits 472
index `vehicleid` of table `ipacket`.`vehicle_image` trx id 5897678083
lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 378 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 4; hex 842c365a; asc ,6Z;;
1: len 4; hex 815d03bc; asc ] ;;
*** (2) TRANSACTION:
TRANSACTION 5897678270, ACTIVE 1 sec inserting, thread declared inside InnoDB 5000
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1248, 2 row lock(s), undo log entries 1
MySQL thread id 873571, OS thread handle 0x11a58, query id 198983849 ec2-35-171-169-21.compute-1.amazonaws.com 35.171.169.21 image_processor update
INSERT INTO vehicle_image (vehicleID, vehicleImageFilePath, vehicleImageSplashFilePath, vehicleImageThumbnailFilePath, vehicleImageMiniFilePath, mainVehicleImage, active)
VALUES (70006326, '29709(1)1522168277.4443843full.jpg', '29709(1)1522168277.4443843splash.jpg', '29709(1)1522168277.4443843thumb.jpg', '29709(1)1522168277.4443843mini.jpg', 1, 1)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 875 page no 238326 n bits 464
index `vehicleid` of table `ipacket`.`vehicle_image` trx id 5897678270
lock_mode X locks gap before rec
Record lock, heap no 378 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 4; hex 842c365a; asc ,6Z;;
1: len 4; hex 815d03bc; asc ] ;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 875 page no 238326 n bits 472
index `vehicleid` of table `ipacket`.`vehicle_image` trx id 5897678270
lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 378 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 4; hex 842c365a; asc ,6Z;;
1: len 4; hex 815d03bc; asc ] ;;
*** WE ROLL BACK TRANSACTION (2)
Я запускаю многие из этих процессов одновременно, но никогда не запускаю два процесса, использующих одно и то же VehicleID
. Я действительно не понимаю, почему я получаю тупики.
Я временно решил проблему, используя уровень изоляции READ COMMITTED
, но я прочитал, что это требует изменений в репликации, так как вы должны выполнять репликацию на уровне строк.
Я читал здесь другие вопросы, которые похожи на мои, но я несколько новичок в SQL и до сих пор не могу понять, почему это происходит.
Подобные вопросы:
- Deadlock на MySQL вставки статистики
- MySQL InnoDB Deadlock Для 2 простых запросов вставки
ОБНОВИТЬ:
Я обнаружил, что использование READ COMMITTED
фактически не решило проблему. Я до сих пор не выяснил, почему возникают тупики, и я действительно не знаю, как диагностировать дальше, чем в настоящее время. Я продолжаю получать тупики в моей производственной системе. Любая помощь будет оценена.
SHOW PROCESSLIST;
. В большинстве случаевREPEATABLE READ
это лучший уровень изоляции для большинства приложений, поэтому я не буду слишком беспокоиться о его использовании. Было ли заметное увеличение производительности, когда вы изменили его по умолчанию -REPEATABLE READ
?VARCHARs
.loop
это просто псевдокод для представления происходящего.repeatable read
кread committed
которой является более низкий уровнем изоляции , то повторяемость чтения, но , к сожалению , это не остановило тупик. Я знаю, что аппаратное обеспечение будет влиять на сервер (это экземпляр ec2, мне нужно было бы посмотреть особенности), но я не думаю, что эта информация была бы необходима, чтобы понять, почему возникают взаимоблокировки. Спорадическая природа этого также затрудняет захват результатов show processlist; когда возникает тупик.Ответы:
Я не эксперт по MySQL, но, судя по вашим журналам тупиковой ситуации, несмотря на то, что вы ВСТАВЛЯЕТЕ разные идентификаторы транспортных средств на оператор, для них требуется блокировка всей страницы данных (238326)
VehicleID
некластеризованного индекса .Тот факт, что вы время от времени получаете взаимоблокировки, означает, что на одной странице у вас есть несколько идентификаторов транспортных средств, поэтому существует небольшая вероятность того, что 2 различным процессам потребуется блокировка для одной и той же страницы.
Лучше всего посоветовать, чтобы ваши транзакции были как можно меньше .
Если есть какой-то способ сделать следующее, это поможет уменьшить вероятность тупика:
Если вы можете, попробуйте изменить коэффициент заполнения этого индекса до 95% , и проверьте, не получите ли вы меньше взаимоблокировок.
Более экстремальное испытание было бы удалить этот индекс полностью, вставляя, а затем воссоздать его , когда сделано.
источник
MySQL не только блокирует затронутую строку, но также затрагивает строку индекса и разрыв между строками индекса (как описано здесь ). Поскольку первичные ключи всегда индексируются, и вы используете их в своих обновлениях, я подозреваю, что несколько транзакций, пытающихся обновить несколько строк, приводят к перекрывающимся блокировкам пробела индекса, которые, в свою очередь, создают тупик.
Чтобы решить эту проблему, я также рекомендую совету Oreos сделать транзакцию как можно меньше. Если обновленные строки не зависят друг от друга, вы должны использовать отдельную транзакцию для каждой из них.
источник