Deadlock zwischen Update- und Insert-Abfragen

9

Ich bin in meiner Anwendung zwischen einer Update- und einer Insert-Abfrage auf einen Deadlock gestoßen, und ich kann nicht verstehen, warum Sperren auf eine Weise gegeben werden, die Deadlock verursacht.

Umgebung -

  • Anwendung - Django
  • Datenbank - MySQL 5.7
  • Motor - Innodb
  • Isolationsstufe - READ COMMITTED.
  • Tabellen (Namen geändert für Sicherheit) -
    1. M - Primärschlüssel - ID
    2. MSC - hat einen Fremdschlüssel für M.id
      • Indizes auf MSC
        1. Index auf M (FK)
        2. Index auf S (FK)
        3. Index über C (FK)
        4. Index für die Eindeutigkeitsbedingung (M, S, C)

Abfragen - Nach zwei Abfragen (Abfragen werden abgeschnitten, um nur relevante Spalten anzuzeigen) -

  • Aktualisieren -

    UPDATE 'MSC' SET 'm_id' = 110, 's_id' = 1234, 'c_id' = '9b39cd', WHERE 'MSC'.'id' = 54362

  • Einfügen -

    INSERT INTO 'MSC' ('m_id', 's_id', 'c_id') VALUES (110, 1235, '9b39cd')

Deadlock -

  • Zuerst wird die Aktualisierungsabfrage ausgelöst und dann wird die Abfrage eingefügt, aber die Ausgabe von SHOW ENGINE INNODB STATUS\G; zeigt an, dass die Abfrage zuvor eingefügt wurde.
  • Von der Ausgabe scheint das Timing ihrer Ausführung in folgender Weise zu sein:
    • Einfügen erhält die exklusive (X) Sperre für MSC und wartet auf die gemeinsame (S) Sperre für den Fremdschlüssel M.
    • Update erhält die exklusive (X) Sperre für M und wartet auf die exklusive (X) Sperre für den Fremdschlüssel MSC.
  • Folgendes ist die vollständige Ausgabe -

%Vor%

Fragen - Ich bin nicht in der Lage, die folgenden zu verstehen 1. Warum musste die Aktualisierungsabfrage warten und konnte die Sperren nicht erhalten, wenn die Abfrage eingab? 2. Warum benötigt die Aktualisierungsabfrage eine exklusive (X) Sperre für die M-Tabelle / nimmt sie an.

Bitte teilen Sie Ihre Gedanken hier. Lassen Sie mich wissen, wenn zusätzliche Informationen erforderlich sind.

    
Saurabh Goyal 06.04.2017, 08:56
quelle

2 Antworten

3

Besteht der ID-Wert von 110 in der M-Tabelle? Es kann auch nützlich sein, diese einzelnen Transaktionen in die Befehle START TRANSACTION; und COMMIT; einzubinden, um sicherzustellen, dass die Einfügung abgeschlossen ist, bevor das Update ausgeführt werden soll.

Beispiel:

%Vor%     
iScript 11.04.2017 20:23
quelle
0

Wie bereits erwähnt, können Ihre beiden Abfragen keinen Deadlock verursachen. Aber mögliche nächste Situation. Zum Beispiel haben wir die nächsten Datensätze in MSC table:

%Vor%

Nun versuchen wir, die nächsten Abfragen parallel auszuführen (ich habe Ihr Update geändert und 1235 anstelle von 1234 geschrieben):

%Vor%

Wir müssen ein Problem mit dem eindeutigen Index auf ( m_id , s_id , c_id ) haben.

Aktualisieren und Einfügen können parallel beginnen, da vor Beginn der Ausführung kein Problem mit der Einschränkung besteht. Aber Abfragen können nicht beendet werden, da sie beide gleiche Zeilen erzeugen müssen und mit einer eindeutigen Einschränkung in Konflikt stehen müssen.

Um diese Situation zu vermeiden, können Sie erzwungene Sperren verwenden. Zum Beispiel

%Vor%

Ich mag keine ähnlichen Schlösser, weil nach diesem Problem hier gelöst werden kann, aber in up-Ebene bewegt. Wenn es möglich ist, überarbeiten Sie Ihr Datenbankschema oder Ihren Algorithmus. Vielleicht finden Sie mehr Eleganz Weg, um Ihre Daten ohne Wahrscheinlichkeit von Deadlocks zu speichern und zu aktualisieren.

    
mnv 15.04.2017 20:48
quelle

Tags und Links