Warum verursacht diese Abfrage Wartezeiten beim Sperren?

7

Von Zeit zu Zeit finde ich viele dieser Fehler in meinem PHP-Fehlerprotokoll:

MYSQL.1213: Deadlock found when trying to get lock; try restarting transactionSQL

Das Problem besteht noch ca. 2 bis 3 Minuten. Dank Stackoverflow war der Grund leicht zu finden:

------------------------
LATEST DETECTED DEADLOCK
------------------------
130320 15:53:37
*** (1) TRANSACTION:
TRANSACTION 0 83395751, ACTIVE 35 sec, process no 26405, OS thread id 140507872417536 starting index read
mysql tables in use 3, locked 3
LOCK WAIT 3 lock struct(s), heap size 1216, 2 row lock(s)
MySQL thread id 1163191, query id 199629038 localhost sosci Updating
UPDATE `database`.`table` SET `invalidate`='2013-03-21 03:53:02' WHERE ((token='C7G8X3HABCDEFGH') AND (invalidate IS NULL)) AND (project=26118) LIMIT 1
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 65548 n bits 192 index `PRIMARY` of table `database`.`table` trx id 0 83395751 lock_mode X locks rec but not gap waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 12; compact format; info bits 0
 0: len 4; hex 000c2591; asc   % ;; 1: len 6; hex 000004e36ace; asc     j ;; 2: len 7; hex 8000000a830110; asc        ;; 3: len 4; hex 80000001; asc     ;; 4: len 4; hex 80006606; asc   f ;; 5: len 1; hex 07; asc  ;; 6: len 16; hex 32455637363853485447444734584252; asc 2EV768SHTGDG4XBR;; 7: SQL NULL; 8: len 30; hex 3935363436362c656e672c616e6e612e63616d706f7265736940676d6169; asc 956466,eng,anna.camporesi@gmai;...(truncated); 9: SQL NULL; 10: len 8; hex 8000124ef477640e; asc    N wd ;; 11: len 8; hex 8000124ef495e88e; asc    N    ;;

*** (2) TRANSACTION:
TRANSACTION 0 83395676, ACTIVE 37 sec, process no 26405, OS thread id 140507856160512 fetching rows, thread declared inside InnoDB 451
mysql tables in use 1, locked 1
4 lock struct(s), heap size 1216, 53 row lock(s), undo log entries 1
MySQL thread id 1163198, query id 199628885 localhost sosci updating
DELETE FROM `database`.`table` WHERE ((action="limit") AND (info='login') AND (creation < DATE_SUB(NOW(), INTERVAL 10 MINUTE)))
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 65548 n bits 192 index `PRIMARY` of table `database`.`table` trx id 0 83395676 lock_mode X
Record lock, heap no 4 PHYSICAL RECORD: n_fields 12; compact format; info bits 0
 0: len 4; hex 000c2591; asc   % ;; 1: len 6; hex 000004e36ace; asc     j ;; 2: len 7; hex 8000000a830110; asc        ;; 3: len 4; hex 80000001; asc     ;; 4: len 4; hex 80006606; asc   f ;; 5: len 1; hex 07; asc  ;; 6: len 16; hex 32455637363853485447444734584252; asc 2EV768SHTGDG4XBR;; 7: SQL NULL; 8: len 30; hex 3935363436362c656e672c616e6e612e63616d706f7265736940676d6169; asc 956466,eng,anna.camporesi@gmai;...(truncated); 9: SQL NULL; 10: len 8; hex 8000124ef477640e; asc    N wd ;; 11: len 8; hex 8000124ef495e88e; asc    N    ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 65548 n bits 192 index `PRIMARY` of table `database`.`table` trx id 0 83395676 lock_mode X waiting
Record lock, heap no 117 PHYSICAL RECORD: n_fields 12; compact format; info bits 0
 0: len 4; hex 000c31d2; asc   1 ;; 1: len 6; hex 000004f884fc; asc       ;; 2: len 7; hex 80000011040110; asc        ;; 3: len 4; hex 80000001; asc     ;; 4: SQL NULL; 5: len 1; hex 06; asc  ;; 6: SQL NULL; 7: len 15; hex 3133322e3139392e3132312e313632; asc 132.199.121.162;; 8: len 5; hex 6c6f67696e; asc login;; 9: len 1; hex 81; asc  ;; 10: len 8; hex 8000124ef49502aa; asc    N    ;; 11: SQL NULL;

*** WE ROLL BACK TRANSACTION (1)

Was ich nicht verstehe ist: Warum? Die gesperrte Tabelle ist sehr klein, nur 61 Einträge (ungefähr 30 neue und 30 gelöschte pro Tag, der automatisch inkrementierte Primärindex liegt nahe 800.000). Keine Spalte ist besonders groß.

Ich verwende das InnoDB-Enging für diese Tabelle (ein Schlüssel bezieht sich auf eine andere Tabelle mit ca. 20.000 Einträgen) und das Problem tritt von Zeit zu Zeit auf. RAM sollte kein Problem sein. Der Webserver und der MySQL-Server werden auf derselben (virtuellen) Maschine ausgeführt, auf der normalerweise keine Leistungsprobleme auftreten. Andere Transaktionen (es gab Tausende während der gesperrten Minuten) in großen Tabellen (1-2 Millionen Einträge) machten keine Probleme.

Danke für deine Hinweise!

BurninLeo
quelle
Ein "Wartezeitlimit für Sperren" und ein "Deadlock" sind zwei völlig verschiedene Dinge, und bei einem Deadlock geht es um das Timing von Ereignissen aus mehr als einem Client-Thread, nicht um "diese Abfrage". Es ist "diese Abfrage" und mindestens eine andere Abfrage von einem anderen Thread und mit ziemlicher Sicherheit frühere Abfragen innerhalb derselben Transaktion. Leider haben Sie nicht alle relevanten Ausgaben SHOW ENGINE INNODB STATUSfür dieses Ereignis veröffentlicht ... das wäre alles von "LATEST DETECTED DEADLOCK" bis zu "WE ROLL BACK TRANSACTION ..."
Michael - sqlbot
Vielen Dank für die Klarstellung bezüglich Timeouts und Deadlocks. Da der Deadlock gleichzeitig mit den Timeout-Fehlern auftritt, wurden die Timeouts meiner Meinung nach durch diesen Deadlock verursacht. Entschuldigung für das Abschneiden der Ausgabe, ich bin noch nicht sehr an die MySQL / InnoDb-Statusinformationen gewöhnt - die fehlenden Informationen wurden jetzt ergänzt.
BurninLeo

Antworten:

8

Erste Transaktion

------------------------
LATEST DETECTED DEADLOCK
------------------------
130320 15:53:37
*** (1) TRANSACTION:
TRANSACTION 0 83395751, ACTIVE 35 sec, process no 26405, OS thread id 140507872417536 starting index read
mysql tables in use 3, locked 3
LOCK WAIT 3 lock struct(s), heap size 1216, 2 row lock(s)
MySQL thread id 1163191, query id 199629038 localhost sosci Updating
UPDATE `database`.`table` SET `invalidate`='2013-03-21 03:53:02' WHERE ((token='C7G8X3HABCDEFGH') AND (invalidate IS NULL)) AND (project=26118) LIMIT 1
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 65548 n bits 192 index `PRIMARY` of table `database`.`table` trx id 0 83395751 lock_mode X locks rec but not gap waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 12; compact format; info bits 0
 0: len 4; hex 000c2591; asc   % ;; 1: len 6; hex 000004e36ace; asc     j ;; 2: len 7; hex 8000000a830110; asc        ;; 3: len 4; hex 80000001; asc     ;; 4: len 4; hex 80006606; asc   f ;; 5: len 1; hex 07; asc  ;; 6: len 16; hex 32455637363853485447444734584252; asc 2EV768SHTGDG4XBR;; 7: SQL NULL; 8: len 30; hex 3935363436362c656e672c616e6e612e63616d706f7265736940676d6169; asc 956466,eng,anna.camporesi@gmai;...(truncated); 9: SQL NULL; 10: len 8; hex 8000124ef477640e; asc    N wd ;; 11: len 8; hex 8000124ef495e88e; asc    N    ;;

Zweite Transaktion

*** (2) TRANSACTION:
TRANSACTION 0 83395676, ACTIVE 37 sec, process no 26405, OS thread id 140507856160512 fetching rows, thread declared inside InnoDB 451
mysql tables in use 1, locked 1
4 lock struct(s), heap size 1216, 53 row lock(s), undo log entries 1
MySQL thread id 1163198, query id 199628885 localhost sosci updating
DELETE FROM `database`.`table` WHERE ((action="limit") AND (info='login') AND (creation < DATE_SUB(NOW(), INTERVAL 10 MINUTE)))
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 65548 n bits 192 index `PRIMARY` of table `database`.`table` trx id 0 83395676 lock_mode X
Record lock, heap no 4 PHYSICAL RECORD: n_fields 12; compact format; info bits 0
 0: len 4; hex 000c2591; asc   % ;; 1: len 6; hex 000004e36ace; asc     j ;; 2: len 7; hex 8000000a830110; asc        ;; 3: len 4; hex 80000001; asc     ;; 4: len 4; hex 80006606; asc   f ;; 5: len 1; hex 07; asc  ;; 6: len 16; hex 32455637363853485447444734584252; asc 2EV768SHTGDG4XBR;; 7: SQL NULL; 8: len 30; hex 3935363436362c656e672c616e6e612e63616d706f7265736940676d6169; asc 956466,eng,anna.camporesi@gmai;...(truncated); 9: SQL NULL; 10: len 8; hex 8000124ef477640e; asc    N wd ;; 11: len 8; hex 8000124ef495e88e; asc    N    ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 65548 n bits 192 index `PRIMARY` of table `database`.`table` trx id 0 83395676 lock_mode X waiting
Record lock, heap no 117 PHYSICAL RECORD: n_fields 12; compact format; info bits 0
 0: len 4; hex 000c31d2; asc   1 ;; 1: len 6; hex 000004f884fc; asc       ;; 2: len 7; hex 80000011040110; asc        ;; 3: len 4; hex 80000001; asc     ;; 4: SQL NULL; 5: len 1; hex 06; asc  ;; 6: SQL NULL; 7: len 15; hex 3133322e3139392e3132312e313632; asc 132.199.121.162;; 8: len 5; hex 6c6f67696e; asc login;; 9: len 1; hex 81; asc  ;; 10: len 8; hex 8000124ef49502aa; asc    N    ;; 11: SQL NULL;

*** WE ROLL BACK TRANSACTION (1)

Was haben Sie gemeinsam ?

Jede Transaktion versucht, eine exklusive Sperre für denselben Teil des PRIMARY KEY zu erhalten: page no 65548 n bits 192

RECORD LOCKS space id 0 page no 65548 n bits 192 index `PRIMARY` of table `database`.`table` trx id 0 83395751 lock_mode X locks rec but not gap waiting
RECORD LOCKS space id 0 page no 65548 n bits 192 index `PRIMARY` of table `database`.`table` trx id 0 83395676 lock_mode X

Daher musste jemand einen Rollback durchführen. Das Ergebnis: Transaktion Nr. 1 wurde zurückgesetzt.

Die Abfrage aus Transaktion 2 muss ausgeführt werden

DELETE FROM `database`.`table` WHERE ((action="limit") AND (info='login') AND (creation < DATE_SUB(NOW(), INTERVAL 10 MINUTE)))

Lesen Sie Ihr Fehlerprotokoll. Irgendwo darin sollte die Rollback-Nachricht sein und die Transaktion Nr. 1 wurde neu gestartet.

Du hast gerade gefragt

Warum hat diese "Situation" den Zugriff auf die Tabelle (oder zumindest auf einige Einträge) für mehr als eine Minute blockiert? Und warum sperren sich die beiden (toten) Transaktionen gegenseitig - anstatt nacheinander auszuführen?

Schauen Sie sich die Schlösser noch einmal an. Jede Transaktion sperrt den PRIMARY KEY. Der PRIMARY KEY befindet sich im Clustered Index ( eine Beschreibung des Clustered Index finden Sie in meinem Beitrag Best of MyISAM und InnoDB ). Bestimmte Schlüssel befinden sich zusammen auf demselben Platz, derselben Seite und demselben Bit. Schauen Sie sich nun die Fragen an:

Transaktion # 1

UPDATE `database`.`table` SET `invalidate`='2013-03-21 03:53:02' WHERE ((token='C7G8X3HABCDEFGH') AND (invalidate IS NULL)) AND (project=26118) LIMIT 1

Transaktion # 2

DELETE FROM `database`.`table` WHERE ((action="limit") AND (info='login') AND (creation < DATE_SUB(NOW(), INTERVAL 10 MINUTE)))

Es ist einfach so, dass der PRIMARY KEY für die zugehörigen Zeilen buchstäblich Mitbewohner sind. Es ist, als würde man zwei olympische Gewichtheber bitten, durch dieselbe Tür zu gehen. Was es noch schlimmer macht, ist, dass die erste Abfrage ein etwas zufälliges Verhalten haben kann. Warum?

Sie ersetzen invalidate(NULL zu dem Zeitpunkt, als Sie mit der Ausführung der Abfrage begonnen haben) durch einen tatsächlichen Datum / Uhrzeit-Wert. Wenn sekundäre (nicht eindeutige Indizes) invalidateals eine der Spalten vorhanden sind, muss der entsprechende PRIMARY KEY gesperrt werden, um die Aktualisierung des Sekundärschlüssels zu stabilisieren. Dies geschieht im Einfügepuffer von ibdata1 (siehe Einfügepuffer in der Map von InnoDB ).

Jede Änderung an einer Spalte, die Mitglied eines oder mehrerer Indizes ist, erfordert eine Sperre des PRIMARY KEY auf Zeilenebene. Leider existieren mehrere Zeilen-IDs auf derselben Seite wie der Clustered Index.

Transaktion Nr. 1 hatte 2 Sperren. Transaktion Nr. 2 hatte 53 Sperren. In einem schicksalhaften Moment wollten sie dieselbe Reihe abschließen. Beachten Sie, dass InnoDB anstelle einer "Perfect World" -Zeilensperrung eine Option zum Festlegen eines längeren Timeout-Werts für Transaktionen ist. Alle DBMS-Produkte müssen sich mit Deadlock Resolution auf LIFO-Basis (Last In, First Out) befassen. Aus diesem Grund durfte Transaktion 2 ohne vollständige Unterbrechung ausgeführt werden.

Geheimnis gelüftet

RolandoMySQLDBA
quelle
Vielen Dank für die Ausgabeerklärung! Was ich immer noch nicht verstehe: Warum hat diese "Situation" den Zugriff auf die Tabelle (oder zumindest auf einige Einträge) für mehr als eine Minute blockiert? Und warum sperren sich die beiden (toten) Transaktionen gegenseitig - anstatt nacheinander auszuführen?
BurninLeo
@ Rolando - Irgendeine Idee, wie man einen solchen Fehler vermeidet. Wir bekommen diese oft in unserer Datenbank, genau ähnliche Fehler. Irgendeine Idee, wie man sie umgeht?
Rishav Rastogi