it-swarm.com.de

"Das Wartezeitlimit für das Sperren wurde überschritten; versuchen Sie, die Transaktion erneut zu starten", obwohl ich keine Transaktion verwende

Ich führe die folgende MySQL-Anweisung UPDATE aus:

mysql> update customer set account_import_id = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

Ich verwende keine Transaktion. Warum sollte ich diesen Fehler erhalten? Ich habe sogar versucht, meinen MySQL-Server neu zu starten, und es half nicht.

Die Tabelle hat 406.733 Zeilen.

192
Jason Swett

Sie verwenden eine Transaktion. Autocommit deaktiviert keine Transaktionen, sondern lässt sie am Ende der Anweisung automatisch ein Commit ausführen.

Was passiert, ist, ein anderer Thread hält eine Datensatzsperre für einen Datensatz (Sie aktualisieren jeden Datensatz in der Tabelle!) Zu lange, und Ihr Thread hat ein Zeitlimit.

Sie können weitere Details zu dem Ereignis anzeigen, indem Sie a ausgeben 

SHOW ENGINE INNODB STATUS

nach dem Ereignis (im sql-Editor). Idealerweise auf einer leisen Testmaschine.

164
MarkR

WIE FORCE UNLOCK für gesperrte Tabellen in MySQL erzwingen:

Wenn Sie solche Sperren aufheben, kann dies dazu führen, dass Atomicity in der Datenbank nicht für die SQL-Anweisungen erzwungen wird, die die Sperre verursacht haben.

Dies ist hackish, und die richtige Lösung besteht darin, die Anwendung zu reparieren, die die Sperren verursacht hat. Wenn jedoch Dollars auf dem Spiel stehen, bringt ein schneller Tritt die Dinge wieder in Gang.

1) Geben Sie MySQL ein

mysql -u your_user -p

2) Sehen wir uns die Liste der gesperrten Tabellen an

mysql> show open tables where in_use>0;

3) Sehen wir uns die Liste der aktuellen Prozesse an, einer davon ist das Sperren Ihrer Tabelle (n).

mysql> show processlist;

4) Töte einen dieser Prozesse

mysql> kill <put_process_id_here>;
252
Eric Leschinski
mysql> set innodb_lock_wait_timeout=100

Query OK, 0 rows affected (0.02 sec)

mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 100   |
+--------------------------+-------+

Jetzt die Sperre erneut auslösen. Sie haben 100 Sekunden Zeit, um einen SHOW ENGINE INNODB STATUS\G an die Datenbank auszustellen und zu sehen, welche andere Transaktion Ihre Transaktion sperrt.

76
veen

Schauen Sie nach, ob Ihre Datenbank fein abgestimmt ist. Besonders die Transaktionsisolation. Es ist keine gute Idee, die Variable innodb_lock_wait_timeout zu erhöhen.

Überprüfen Sie die Isolationsstufe Ihrer Datenbanktransaktionen in mysql cli:

mysql> SELECT @@GLOBAL.tx_isolation, @@tx_isolation, @@session.tx_isolation;
+-----------------------+-----------------+------------------------+
| @@GLOBAL.tx_isolation | @@tx_isolation  | @@session.tx_isolation |
+-----------------------+-----------------+------------------------+
| REPEATABLE-READ       | REPEATABLE-READ | REPEATABLE-READ        |
+-----------------------+-----------------+------------------------+
1 row in set (0.00 sec)

Sie könnten Verbesserungen erhalten, die die Isolationsstufe ändern, indem Sie Oracle wie READ COMMITTED statt REPEATABLE READ (InnoDB Defaults) verwenden

mysql> SET tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> 

Verwenden Sie SELECT FOR UPDATE auch nur, wenn nötig.

62
saisyukusanagi

Keine der vorgeschlagenen Lösungen funktionierte für mich, aber dies tat es.

Die Ausführung der Abfrage wird durch etwas blockiert. Wahrscheinlich wird eine andere Abfrage in einer der Tabellen Ihrer Abfrage aktualisiert, eingefügt oder gelöscht. Sie müssen herausfinden, was das ist:

SHOW PROCESSLIST;

Wenn Sie den Blockierungsprozess gefunden haben, suchen Sie seine id und führen Sie Folgendes aus: 

KILL {id};

Führen Sie Ihre erste Abfrage erneut aus.

12
BassMHL

100% mit dem, was MarkR gesagt hat. autocommit macht jede Anweisung zu einer Transaktion mit einer Anweisung.

SHOW ENGINE INNODB STATUS sollte Ihnen Hinweise auf den Deadlock-Grund geben. Schauen Sie sich auch das langsame Abfrageprotokoll genau an, um zu sehen, was sonst die Tabelle abfragt, und versuchen Sie, alles zu entfernen, was einen vollständigen Tablescan durchführt. Das Sperren auf Zeilenebene funktioniert gut, aber nicht, wenn Sie versuchen, alle Zeilen zu sperren!

12
James C

Können Sie einen anderen Datensatz innerhalb dieser Tabelle aktualisieren oder wird diese Tabelle stark verwendet? Was ich denke, ist, dass, während versucht wird, eine Sperre zu erwerben, die zum Aktualisieren dieses Datensatzes erforderlich ist, das eingestellte Timeout abgelaufen ist. Möglicherweise können Sie die Zeit verlängern, die helfen kann.

5
John Kane

Die Anzahl der Zeilen ist nicht sehr groß ... Erstellen Sie einen Index für account_import_id, wenn er nicht der Primärschlüssel ist.

CREATE INDEX idx_customer_account_import_id ON customer (account_import_id);
1
gladiator

Stellen Sie sicher, dass die Datenbanktabellen die InnoDB-Speicher-Engine und die Isolationsstufe READ-COMMITTED verwenden.

Sie können es überprüfen, indem Sie SELECT @@ GLOBAL.tx_isolation, @@ tx_isolation; auf der MySQL-Konsole.

Wenn es nicht auf READ-COMMITTED eingestellt ist, müssen Sie es einstellen. Stellen Sie vor dem Einstellen sicher, dass Sie SUPER-Berechtigungen in mysql haben.

Hilfe erhalten Sie unter http://dev.mysql.com/doc/refman/5.0/de/set-transaction.html .

Mit dieser Einstellung glaube ich, dass Ihr Problem gelöst wird.


Möglicherweise möchten Sie auch prüfen, ob Sie nicht versuchen, dies in zwei Prozessen gleichzeitig zu aktualisieren. Benutzer (@tala) sind in diesem Kontext auf ähnliche Fehlermeldungen gestoßen. Überprüfen Sie möglicherweise, ob ...

1
Ravi Chhatrala

Diese Art von Sache ist mir passiert, als ich php mitten in der Transaktion. Dann "hängt" diese -Transaktion und Sie müssen den mysql-Prozess beenden (oben beschrieben mit processlist;)

0
TomoMiha

In meiner Instanz führte ich eine abnormale Abfrage aus, um Daten zu korrigieren. Wenn Sie die Tabellen in Ihrer Abfrage sperren, müssen Sie sich nicht mit dem Sperrzeitlimit befassen:

LOCK TABLES `customer` WRITE;
update customer set account_import_id = 1;
UNLOCK TABLES;

Dies ist wahrscheinlich keine gute Idee für den normalen Gebrauch.

Weitere Informationen finden Sie unter: MySQL 8.0 Referenzhandbuch

0
Jeff Luyet

Später zur Party (wie üblich) war mein Problem jedoch die Tatsache, dass ich schlechtes SQL (ein Anfänger) geschrieben habe und mehrere Prozesse eine Sperre für die Datensätze hatten <- nicht die richtige Aussage. Am Ende musste ich einfach: SHOW PROCESSLIST und dann die IDs mit KILL <id> beenden

0
Smitty

Ich bin auf diese mit 2 Doctrine DBAL-Verbindungen gestoßen, eine davon als nicht-transaktional (für wichtige Protokolle), sie sollen parallel laufen, ohne voneinander abhängig zu sein.

CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery()
)

Meine Integrationstests wurden nach einem Test in Transaktionen für das Daten-Rollback eingebunden.

beginTransaction()
CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery() // CONFLICT
)
rollBack()

Meine Lösung bestand darin, die Wrapping-Transaktion in diesen Tests zu deaktivieren und die DB-Daten auf andere Weise zurückzusetzen.

0
Fabian Picone

Wenn Sie gerade eine große Abfrage beendet haben, dauert es eine Weile bis rollback. Wenn Sie eine weitere Abfrage ausgeben, bevor die abgebrochene Abfrage rückgängig gemacht wird, wird möglicherweise ein Zeitüberschreitungsfehler angezeigt. Das ist mir passiert. Die Lösung bestand nur darin, etwas zu warten.

Einzelheiten:

Ich hatte eine DELETE-Abfrage ausgegeben, um etwa 900.000 von etwa 1 Million Zeilen zu entfernen.

Ich habe dies aus Versehen ausgeführt (entfernt nur 10% der Zeilen): DELETE FROM table WHERE MOD(id,10) = 0

Stattdessen (entfernt 90% der Zeilen): DELETE FROM table WHERE MOD(id,10) != 0

Ich wollte 90% der Zeilen entfernen, nicht 10%. Also habe ich den Prozess in der MySQL-Befehlszeile beendet, da ich wusste, dass dadurch alle bisher gelöschten Zeilen rückgängig gemacht werden.

Dann habe ich sofort den richtigen Befehl ausgeführt und kurz darauf einen lock timeout exceeded-Fehler erhalten. Mir wurde klar, dass die Sperre tatsächlich die rollback der abgebrochenen Abfrage sein könnte, die sich noch im Hintergrund abspielt. Also habe ich ein paar Sekunden gewartet und die Abfrage erneut ausgeführt.

0
Buttle Butkus

Ich kam von Google und wollte nur die Lösung hinzufügen, die für mich funktioniert. Mein Problem war, dass ich versucht habe, Datensätze einer riesigen Tabelle zu löschen, die eine Menge FK in Kaskade hatte, sodass ich den gleichen Fehler wie das OP erhalten habe.

Ich habe die autocommit deaktiviert und dann hat es funktioniert, einfach COMMIT am Ende des SQL-Satzes hinzuzufügen. Soweit ich verstanden habe, wird der Puffer nach und nach freigegeben, anstatt am Ende des Befehls zu warten.

Um am Beispiel des OP festzuhalten, hätte dies funktionieren müssen:

mysql> set autocommit=0;

mysql> update customer set account_import_id = 1; commit;

Vergessen Sie nicht, die autocommit erneut zu aktivieren, wenn Sie die MySQL-Konfiguration wie zuvor verlassen möchten.

mysql> set autocommit=1;

0
Kamae