J'obtiens des verrous mortels à partir de verrous d'espacement sur une table lorsque j'insère fréquemment dedans à partir de plusieurs sources. Voici un aperçu de mes processus.
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
La sortie de SHOW Create table vehicle_image;
est:
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
Et le dernier Deadlock donné par 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)
J'exécute plusieurs de ces processus simultanément, mais je n'exécute jamais deux processus qui utilisent le même VehicleID
. Je ne comprends vraiment pas pourquoi je reçois des blocages.
J'ai résolu temporairement le problème en utilisant le niveau d'isolement READ COMMITTED
, mais j'ai lu que cela nécessite des modifications de réplication dans la mesure où vous devez effectuer une réplication au niveau des lignes.
J'ai lu d'autres questions ici qui sont similaires aux miennes, mais je suis un peu nouveau pour SQL et je ne comprends toujours pas pourquoi cela se produit.
Questions similaires:
- Blocage sur les insertions MySQL
- Blocage MySQL InnoDB Pour 2 requêtes d'insertion simples
MISE À JOUR:
J'ai découvert que l'utilisation READ COMMITTED
n'a pas vraiment résolu le problème. Je n'ai toujours pas compris pourquoi les blocages se produisent et je ne sais vraiment pas comment diagnostiquer plus loin que ce que j'ai actuellement. Je continue d'avoir des impasses dans mon système de production. Toute aide serait appréciée.
SHOW PROCESSLIST;
. La plupart du temps,REPEATABLE READ
c'est le meilleur niveau d'isolement pour la plupart des applications, donc je ne serais pas trop préoccupé par son utilisation. Y a-t-il eu une augmentation notable des performances lorsque vous l'avez modifiée par défaut -REPEATABLE READ
?VARCHARs
.loop
pseudocode est juste pour représenter ce qui se passe.repeatable read
àread committed
qui est un niveau d'isolation plus faible puis de lecture répétée, mais malheureusement cela n'a pas empêché les blocages. Je sais que le matériel affectera le serveur (c'est une instance ec2, je devrais rechercher des détails) mais je ne pense pas que ces informations seraient nécessaires pour comprendre pourquoi les blocages se produisent. La nature sporadique de ceci rend également difficile la capture de la sortie de show processlist; lorsque l'impasse se produit.Réponses:
Je ne suis pas un expert MySQL, mais d'après l'apparence de vos journaux Deadlock, même si vous insérez différents ID de véhicule par instruction, ceux-ci nécessitent que la page de données entière (238326) de l'
VehicleID
index non cluster soit verrouillée .Le fait que vous ayez parfois des blocages signifie que sur 1 page, vous avez plusieurs ID de véhicule, il y a donc une petite chance que 2 processus différents aient besoin d'un verrou pour la même page.
La meilleure chose à conseiller est de garder vos transactions aussi petites que possible .
S'il existe un moyen de procéder comme suit, cela contribuera à réduire les risques de blocage:
Si vous le pouvez, essayez de changer le facteur de remplissage de cet index à 95% et testez pour voir si vous obtenez moins de blocages.
Un test plus extrême serait de supprimer complètement cet index lors de l'insertion, puis de le recréer une fois terminé.
la source
MySQL verrouille non seulement la ligne affectée, mais également la ligne d'index affectée et l'écart entre les lignes d'index (comme décrit ici ). Étant donné que les clés primaires sont toujours indexées et que vous les utilisez dans vos mises à jour, je soupçonne que plusieurs transactions essayant de mettre à jour plusieurs lignes entraînent chacune des verrous d'écart d'index qui se chevauchent, ce qui crée à son tour le blocage.
Pour résoudre ce problème, je recommande également les conseils d'Oreos pour maintenir une transaction aussi petite que possible. Si les lignes mises à jour sont indépendantes les unes des autres, vous devez utiliser une transaction distincte pour chacune d'entre elles.
la source