2010-03-18 10 views
10

Ich habe die folgende Abfrage (alle Tabellen sind InnoDB)wie man vermeiden Deadlock in mysql

INSERT INTO busy_machines(machine) 
       SELECT machine FROM all_machines 
       WHERE machine NOT IN (SELECT machine FROM busy_machines) 
       and machine_name!='Main' 
       LIMIT 1 

, die eine Sackgasse führt, wenn ich es in Threads ausgeführt, offensichtlich wegen der inneren wählen, nicht wahr?

Der Fehler, den ich bekommen ist:

(1213, 'Deadlock found when trying to get lock; try restarting transaction') 

Wie kann ich den Stillstand vermeiden? Gibt es eine Möglichkeit, die Abfrage zu ändern, damit sie funktioniert, oder muss ich etwas anderes tun?

Der Fehler passiert nicht immer, natürlich, nur nach dem Ausführen dieser Abfrage viele Male und in mehreren Threads.

+0

Sind Sie erleben Deadlock oder Sperr-Konflikt? – Quassnoi

+0

@Quassnoi: Ich habe die Info zu der Frage hinzugefügt - (1213, "Deadlock gefunden, wenn Sie versuchen, Sperre zu bekommen; versuchen, Transaktion neu zu starten") – olamundo

+0

'show innodb status' würde kurz die Ursache der letzten Deadlock beschreiben – jonny

Antwort

5

Sie werden wahrscheinlich eine bessere Leistung erhalten, wenn Sie Ihr "NOT IN" durch eine äußere Verbindung ersetzen.

Sie können diese Abfrage auch in zwei Abfragen aufteilen, um das Einfügen und Auswählen derselben Tabelle in einer einzelnen Abfrage zu vermeiden.

Etwas wie folgt aus:

  SELECT a.machine 
      into @machine 
      FROM all_machines a 
      LEFT OUTER JOIN busy_machines b on b.machine = a.machine 
      WHERE a.machine_name!='Main' 
      and b.machine IS NULL 
      LIMIT 1; 

      INSERT INTO busy_machines(machine) 
      VALUES (@machine); 
+0

Dies ist eine großartige Lösung, wenn Sie MySQL 5.0 oder höher verwenden, sonst stehen Ihnen keine Benutzervariablen zur Verfügung. Dies sollte auch Ihre Deadlock-Probleme vermeiden. –

+0

Ich verstehe nicht, wie ist Ihre Abfrage ähnlich wie meine - die äußere Verknüpfung wird auch Maschinen, die in stark ausgelasteten Maschinen sind, und nicht nur diejenigen, die nicht – olamundo

+0

@noam sind, mit der äußeren Verknüpfung kombiniert mit "und b.Machine IS NULL "in der where-Klausel schließt die Maschinen aus, die sich in busy_machines befinden. Es wird die gleichen Daten wie das NOT IN zurückgeben, aber so viel effizienter. –

11

Zu meinem Verständnis, eine Auswahl nicht Sperre erhalten und sollte nicht die Ursache für den Deadlock sein.

Jedes Mal, wenn Sie eine Zeile einfügen/aktualisieren/löschen, wird eine Sperre erfasst. Um Deadlocks zu vermeiden, müssen Sie sicherstellen, dass bei gleichzeitigen Transaktionen die Zeile nicht in einer Reihenfolge aktualisiert wird, die zu einem Deadlock führen kann. Im Allgemeinen, um Deadlock zu vermeiden, müssen Sie Sperre immer in der gleichen Reihenfolge erwerben sogar in anderer Transaktion (z. B. immer zuerst Tabelle A, dann Tabelle B).

Aber wenn innerhalb einer Transaktion in nur einer Tabelle einfügen diese Bedingung erfüllt ist, und dies sollte dann in der Regel nicht zu einem Deadlock führen. Machst du etwas anderes in der Transaktion?

Ein Deadlock kann jedoch auftreten, wenn fehlende Indizes fehlen. Wenn eine Zeile eingefügt/aktualisiert/gelöscht wird, muss die Datenbank die relationalen Einschränkungen überprüfen, dh sicherstellen, dass die Beziehungen konsistent sind. Um dies zu tun, muss die Datenbank die Fremdschlüssel in den zugehörigen Tabellen überprüfen. Es könnte Ergebnis in anderen Sperre erworben werden als die Zeile, die geändert wird. Stellen Sie sicher, dass Sie immer einen Index für die Fremdschlüssel (und natürlich für die Primärschlüssel) haben, andernfalls könnte ein Tabellenschloss anstelle eines Zeilenschlosses entstehen. Wenn die Tabellensperre auftritt, ist die Sperrkonflikt höher und die Wahrscheinlichkeit von Deadlock erhöht.

Nicht sicher, was genau in Ihrem Fall passiert, aber vielleicht hilft es.

+0

-1; MySQL erlaubt Ihnen nicht einmal, einen Fremdschlüssel zwischen zwei Spalten zu erstellen, es sei denn, beide Indizes sind indiziert. Daher können fehlende Indizes für Fremdschlüssel nichts erklären. –