Warum sollte MySQL eine gemeinsame Sperre anfordern, nachdem die Transaktionsebene auf READ UNCOMMITTED gesetzt wurde?


7

Ausführen eines Verarbeitungsjobs in mehreren parallelen Stapeln, bei dem im Grunde genommen große Zeilenblöcke gelesen werden, um einige zu aktualisieren. Hier ist es in Ordnung, eine niedrigere Transaktionsebene zu verwenden, da ich weiß, dass die relevanten Werte nicht aktualisiert werden, während diese Aufgabe ausgeführt wird, bevor die einzelnen gespeicherten aufgerufen werden proc Ich laufe:

set session transaction isolation level read uncommitted

Rufen Sie dann den gespeicherten Prozess auf, der eine Teilmenge der zu verarbeitenden IDs erhält. SQLFiddle der Gesamtoperation: http://sqlfiddle.com/#!9/192d62 (etwas erfunden, behält aber die Struktur der ursprünglichen Abfragen bei)

Der Grund, den ich frage, ist, dass die Deadlocks weiterhin auftreten und in der Monitorausgabe ein Thread eine gemeinsam genutzte Sperre anfordert, während ein anderer eine exklusive Sperre über denselben Speicherplatz hält (oder umgekehrt) - sollte das Festlegen dieser Transaktionsebene die Notwendigkeit nicht verhindern für eine gemeinsame Sperre? Gibt es einen Grund, eine gemeinsame Sperre aufzuheben repeatable-read?

InnoDB verwenden.

Relevante show engine innodb statusSperrinformationen von (bearbeitet, um mit dem Tabellennamen von SQLFiddle übereinzustimmen):

*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 481628 page no 24944 n bits 112 index `PRIMARY` of table `events` trx id 27740892 lock mode S locks rec but not gap waiting

und

*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 481628 page no 24944 n bits 112 index `PRIMARY` of table `events` trx id 27740898 lock_mode X locks rec but not gap waiting

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 481628 page no 25267 n bits 112 index `PRIMARY` of table `events` trx id 27740898 lock_mode X locks rec but not gap waiting

Beachten Sie, dass die Abfragen 1 und 2 in der SQLFiddle mit den ersten und zweiten Einträgen in der Engine-Ausgabe übereinstimmen. Der PRIMARYSchlüssel befindet sich nur über der idSpalte (wie in der Geige zu sehen ist)


Antworten:


1

"Lesen Sie Chunks, aber aktualisieren Sie nur einige davon" ...

SELECT a chunk -- separate transaction, don't care about locking, etc
munch on that chunk to figure out the 'few' ids to update
BEGIN;
    SELECT ... WHERE id IN (list of the few) FOR UPDATE;
    minimal other work
    UPDATE them;
COMMIT;   -- plus checks for deadlocks, etc, and restart the code.

Die Idee ist, so viel zeitaufwändigen Code wie möglich aus der Transaktion herauszuholen , um die Transaktion zu beschleunigen und so die Wahrscheinlichkeit von Konflikten zu minimieren. (Nein, es wird wahrscheinlich nicht alle Deadlocks beseitigen , aber es sollte helfen.)

Noch ein Hinweis: Wenn möglich, gehen Sie die Tabelle in allen Threads in derselben Reihenfolge durch. Deadlocks treten auf, wenn ein Thread spielt id IN (1,2), ein anderer jedoch IN (2,1). Wenn beides der IN (1,2)Fall ist, kommt es zu Verzögerungen und nicht zu Deadlocks.

Ein weiterer Tipp: Verkleinern Sie die Brocken.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.