Ich erhalte Deadlocks von Lückenschlössern auf einer Tabelle, wenn ich sie häufig aus mehreren Quellen einfüge. Hier ist eine Übersicht meiner Prozesse.
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
Die Ausgabe von SHOW Create table vehicle_image;
ist:
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
Und der letzte Deadlock von 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)
Ich führe viele dieser Prozesse gleichzeitig aus, aber niemals zwei Prozesse, die denselben verwenden VehicleID
. Ich bin wirklich verwirrt, warum ich Deadlocks bekomme.
Ich habe das Problem vorübergehend mithilfe der Isolationsstufe gelöst READ COMMITTED
, aber ich habe gelesen, dass dies Änderungen an der Replikation erfordert, da Sie die Replikation auf Zeilenebene durchführen müssen.
Ich habe hier andere Fragen gelesen, die meinen ähnlich sind, aber ich bin etwas neu in SQL und kann immer noch nicht verstehen, warum dies geschieht.
Ähnliche Fragen:
- Deadlock bei MySQL-Insert-Anweisungen
- MySQL InnoDB Deadlock Für 2 einfache Insert-Abfragen
AKTUALISIEREN:
Ich fand heraus, dass die Verwendung READ COMMITTED
das Problem nicht wirklich gelöst hat. Ich habe immer noch nicht herausgefunden, warum die Deadlocks auftreten, und ich weiß wirklich nicht, wie ich weiter diagnostizieren soll, als ich es derzeit getan habe. Ich bekomme weiterhin Deadlocks in mein Produktionssystem. Jede Hilfe wäre dankbar.
SHOW PROCESSLIST;
. MeistensREPEATABLE READ
ist dies die beste Isolationsstufe für die meisten Apps, daher würde ich mir keine Sorgen um die Verwendung machen. Gab es eine spürbare Leistungssteigerung, als Sie die Standardeinstellung geändert habenREPEATABLE READ
?VARCHARs
.loop
nur ein Pseudocode ist, um darzustellen, was gerade stattfindet.repeatable read
anread committed
dem eine untere Isolationsstufe dann wiederholbare lesen, aber leider hat es nicht die Deadlocks zu stoppen. Ich weiß, dass die Hardware den Server beeinflusst (es ist eine ec2-Instanz, ich müsste nach Einzelheiten suchen), aber ich denke nicht, dass diese Informationen notwendig wären, um zu verstehen, warum die Deadlocks auftreten. Die sporadische Natur macht es auch schwierig, die Ausgabe der Show-Prozessliste zu erfassen. wenn der Deadlock auftritt.Antworten:
Ich bin kein MySQL-Experte, aber nach dem Aussehen Ihrer Deadlock-Protokolle muss die gesamte Datenseite (238326) des
VehicleID
nicht gruppierten Index gesperrt werden , obwohl Sie pro Anweisung unterschiedliche Fahrzeug-IDs einfügen .Die Tatsache, dass Sie gelegentlich Deadlocks erhalten, bedeutet, dass Sie innerhalb einer Seite mehrere Fahrzeug-IDs haben. Daher besteht eine geringe Wahrscheinlichkeit, dass zwei verschiedene Prozesse eine Sperre für dieselbe Seite benötigen.
Am besten raten Sie , Ihre Transaktionen so klein wie möglich zu halten .
Wenn Sie auf folgende Weise Folgendes tun können, verringert sich die Wahrscheinlichkeit eines Deadlocks:
Wenn Sie können, versuchen Sie, den Füllfaktor dieses Index auf 95% zu ändern , und testen Sie, ob Sie weniger Deadlocks erhalten.
Ein extremerer Test wäre , diesen Index beim EINFÜGEN vollständig zu entfernen und ihn anschließend neu zu erstellen .
quelle
MySQL sperrt nicht nur die betroffene Zeile, sondern auch die betroffene Indexzeile und die Lücke zwischen den Indexzeilen (wie hier beschrieben ). Da Primärschlüssel immer indiziert sind und Sie sie in Ihren Aktualisierungen verwenden, vermute ich, dass mehrere Transaktionen, die versuchen, mehrere Zeilen zu aktualisieren, zu überlappenden Indexlückensperren führen, die wiederum den Deadlock verursachen.
Um dies zu beheben, empfehle ich auch den Rat von Oreos, eine Transaktion so klein wie möglich zu halten. Wenn die aktualisierten Zeilen unabhängig voneinander sind, sollten Sie für jede Zeile eine separate Transaktion verwenden.
quelle