In der Nacht habe ich viele Probleme mit Zeilensperren. Der umstrittene Tisch scheint ein bestimmter Tisch zu sein.
Dies ist im Allgemeinen, was passiert -
- Entwickler 1 startet eine Transaktion über den Oracle Forms-Frontend-Bildschirm
- Entwickler 2 startet eine andere Transaktion aus einer anderen Sitzung und verwendet dabei denselben Bildschirm
~ 5 Minuten später scheint das Frontend nicht zu reagieren. Das Überprüfen von Sitzungen zeigt Zeilensperrenkonflikte. Die "Lösung", die jeder herumwirft, ist, Sitzungen zu beenden: /
Als Datenbankentwickler
- Was kann getan werden, um Reihensperrkonflikte zu beseitigen?
- Wäre es möglich, herauszufinden, welche Zeile einer gespeicherten Prozedur diese Zeilensperrkonflikte verursacht?
- Was wäre die allgemeine Richtlinie, um solche Probleme zu reduzieren, zu vermeiden oder zu beseitigen, welche Codierung?
Wenn diese Frage zu offen / unzureichend ist, können Sie sie gerne bearbeiten / mich informieren. Ich werde mein Bestes tun, um einige zusätzliche Informationen hinzuzufügen.
Die betreffende Tabelle enthält viele Einfügungen und Aktualisierungen. Ich würde sagen, es handelt sich um eine der am stärksten frequentierten Tabellen. Der SP ist ziemlich komplex - um es zu vereinfachen - er holt Daten aus verschiedenen Tabellen, füllt sie in Arbeitstabellen, viele arithmetische Operationen finden in der Arbeitstabelle statt und das Ergebnis der Arbeitstabelle wird in die betreffende Tabelle eingefügt / aktualisiert.
Die Datenbankversion ist Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - 64bit. Der Ablauf der Logik wird in beiden Sitzungen in derselben Reihenfolge ausgeführt, die Transaktion wird nicht zu lange offen gehalten (oder zumindest denke ich ), und die Sperren treten während der aktiven Ausführung von Transaktionen auf.
Update: Die Anzahl der Tabellenzeilen ist mit etwa 3,1 Millionen Zeilen größer als erwartet. Nach dem Verfolgen einer Sitzung stellte ich außerdem fest, dass einige Aktualisierungsanweisungen für diese Tabelle den Index nicht verwenden. Warum ist es so - ich bin nicht sicher. Die Spalte, auf die in der where-Klausel verwiesen wird, ist indiziert. Ich erstelle gerade den Index neu.
quelle
COMMIT
oderROLLBACK
in einer angemessenen Zeit oder b) so zu arrangieren, dass dieselben Leute nicht immer dieselbe Reihe zur selben Zeit wollen.Antworten:
Nicht genau, aber Sie können die SQL-Anweisung abrufen, die die Sperre verursacht, und die zugehörigen Zeilen in der Prozedur identifizieren.
Im Oracle Concepts Guide-Abschnitt zu Sperren heißt es: "Eine Zeile ist nur gesperrt, wenn sie von einem Writer geändert wurde." Eine weitere Sitzung die gleiche Zeile Aktualisierung wird dann warten , bis die erste Sitzung
COMMIT
oderROLLBACK
bevor es weitergehen kann. Um das Problem zu beheben, können Sie die Benutzer serialisieren. Hier sind jedoch einige Punkte, die das Problem möglicherweise so weit reduzieren können, dass es kein Problem darstellt.COMMIT
häufiger. Mit jedemCOMMIT
Aufheben von Sperren wird die Wahrscheinlichkeit verringert, dass eine andere Sitzung dieselbe Zeile benötigt, wenn Sie die Aktualisierungen in Stapeln durchführen können.UPDATE t1 SET f1=DECODE(f2,’a’,f1+1,f1);
sollte als selektiver umgeschrieben werden (weniger Sperren lesen)UPDATE t1 SET f1=f1+1 WHERE f2=’a’;
. Wenn die Änderung der Anweisung weiterhin die meisten Zeilen in der Tabelle sperrt, hat die Änderung natürlich nur einen Vorteil für die Lesbarkeit.BULK COLLECT ... FORALL
.UPDATE
und dem letzten ausgeführt wirdCOMMIT
. Wenn der Code beispielsweise nach jedem Update eine E-Mail sendet, sollten Sie die E-Mails in die Warteschlange stellen und sie nach dem Festschreiben der Updates senden.SELECT ... FOR UPDATE NOWAIT
oderWAIT 2
. Sie können dann feststellen, dass die Zeile nicht gesperrt werden kann, und den Benutzer darüber informieren, dass in einer anderen Sitzung dieselben Daten geändert werden.quelle
Ich werde eine Antwort aus Entwicklersicht geben.
Meiner Meinung nach liegt es an einem Fehler in Ihrer Anwendung, wenn Sie auf einen Zeilenkonflikt stoßen, wie den, den Sie beschreiben. In den meisten Fällen handelt es sich bei dieser Art von Konflikten um ein Anzeichen für eine Sicherheitsanfälligkeit aufgrund eines verlorenen Updates. Dieser Thread auf AskTom erklärt das Konzept eines verlorenen Updates:
Sie haben eine böse Nebenwirkung des verlorenen Updates erlebt: Sitzung 2 kann blockiert werden, da Sitzung 1 noch nicht festgeschrieben wurde. Das Hauptproblem ist jedoch, dass Sitzung 2 den Datensatz blind aktualisiert. Angenommen, beide Sitzungen geben die folgende Anweisung aus:
Nach beiden Anweisungen wurden die Änderungen von Sitzung1 überschrieben, ohne dass Sitzung2 darüber informiert wurde, dass die Zeile von Sitzung 1 geändert wurde.
Verlorene Updates (und der Nebeneffekt von Konflikten) sollten niemals auftreten, sie sind zu 100% vermeidbar. Sie sollten das Sperren verwenden, um dies mit zwei Hauptmethoden zu verhindern: dem optimistischen und dem pessimistischen Sperren .
1) Pessimistisches Sperren
Sie möchten eine Zeile aktualisieren. In diesem Modus verhindern Sie, dass andere Benutzer diese Zeile ändern, indem Sie eine Sperre für diese Zeile anfordern (
SELECT ... FOR UPDATE NOWAIT
Anweisung). Wenn die Zeile bereits geändert wird, wird eine Fehlermeldung angezeigt, die Sie ordnungsgemäß an den Endbenutzer übertragen können (diese Zeile wird von einem anderen Benutzer geändert). Wenn die Zeile verfügbar ist, nehmen Sie Ihre Änderungen vor (UPDATE) und bestätigen Sie, wann immer Ihre Transaktion abgeschlossen ist.2) Optimistisches Sperren
Sie möchten eine Zeile aktualisieren. Sie möchten jedoch keine Sperre für diese Zeile aufrechterhalten, weil Sie möglicherweise mehrere Transaktionen zum Aktualisieren der Zeile verwenden (webbasierte Anwendung ohne Status) oder weil Sie nicht möchten, dass ein Benutzer eine Sperre zu lange hält ( Dies kann dazu führen, dass andere Personen blockiert werden. In diesem Fall werden Sie nicht sofort eine Sperre anfordern. Sie werden einen Marker verwenden, um sicherzustellen, dass sich die Zeile nicht geändert hat, wenn Ihr Update veröffentlicht wird. Sie können den Wert aller Spalten zwischenspeichern oder eine Zeitstempelspalte, die automatisch aktualisiert wird, oder eine sequenzbasierte Spalte verwenden. Unabhängig von Ihrer Wahl stellen Sie bei der Durchführung des Updates sicher, dass sich die Markierung in dieser Zeile nicht geändert hat, indem Sie eine Abfrage wie die folgende absenden:
Wenn die Abfrage eine Zeile zurückgibt, führen Sie Ihre Aktualisierung durch. Wenn dies nicht der Fall ist, bedeutet dies, dass die Zeile seit Ihrer letzten Abfrage geändert wurde. Sie müssen den Vorgang von Anfang an neu starten.
Hinweis: Wenn Sie allen Anwendungen, die auf Ihre Datenbank zugreifen, vollkommen vertrauen, können Sie sich auf ein direktes Update für das optimistische Sperren verlassen. Sie könnten direkt ausstellen:
Wenn die Anweisung keine Zeile aktualisiert, wissen Sie, dass jemand diese Zeile geändert hat und Sie müssen von vorne beginnen.
Wenn alle Anwendungen diesem Schema zustimmen, werden Sie niemals von einer anderen Person blockiert und vermeiden das blinde Update. Wenn Sie die Zeile jedoch nicht im Voraus sperren, besteht weiterhin die Gefahr einer unbefristeten Sperre, wenn eine andere Anwendung, ein Stapeljob oder eine direkte Aktualisierung keine optimistische Sperre implementiert. Aus diesem Grund empfehle ich, die Zeile unabhängig von der Auswahl des Sperrschemas immer zu sperren (der Leistungseinbruch kann vernachlässigbar sein, da Sie beim Sperren der Zeile alle Werte einschließlich der Zeilen-ID abrufen).
TL; DR
quelle
Diese Antwort würde wahrscheinlich für einen Eintrag in The Daily WTF qualifizieren.
Richtig, nachdem die Sitzungen verfolgt und gerade
USER_SOURCE
- ich aufgespürt die Ursachequelle