2012-04-09 5 views
8

Ich bin mit einem Deadlock-Problem von einer PL/pgSQL-Funktion in meiner PostgreSQL-Datenbank konfrontiert. Sie finden die SQL-Anweisung in dem Codeblock (nur Beispiel):Deadlock in PL/pgSQL-Funktion erkannt

BEGIN 
UPDATE accounts SET balance = 0 WHERE acct_name like 'A%'; 
UPDATE accounts SET balance = balance + 100 WHERE acct_name like '%A'; 
EXCEPTION WHEN OTHERS THEN RAISE NOTICE SQLERRM; 
END; 

Ich habe festgestellt, dass der Stillstand in dieser Erklärung aufgetreten ausgeführt wurde. Aber ich bin mir nicht sicher, ob es andere Anweisungen gab, die versuchten, diese Tabelle zur gleichen Zeit zu aktualisieren (weil ich keine in meinem Logging-System gefunden hatte).

Also, ist es möglich, dass der Deadlock innerhalb dieser Aussage aufgetreten ist? Soweit ich weiß, wenn wir die ganze Aussage mit BEGIN/END blockiert. Es wird dieselbe Transaktion geben und sollte nicht von selbst gesperrt werden.

+0

Haben Sie Trigger auf Konten? Verwenden Sie auch explizites Sperren? – strkol

+1

Standardmäßig kann eine Transaktion Änderungen beobachten, die von anderen Transaktionen ausgeführt wurden. Weitere Informationen finden Sie unter [Transaktionsisolation] (http://www.postgresql.org/docs/current/static/transaction-iso.html) in der PostgreSQL-Dokumentation. –

+0

@strkol Ja, ich habe, aber die Aussage in diesem Trigger ist nicht mit dieser Tabelle verbunden. Für das explizite Sperren gibt es ja auch. –

Antwort

11

Es gibt definitiv ein anderes Verfahren im Wettbewerb um die gleiche Ressource. Das ist die Natur einer Sackgasse. Eine Funktion wie Sie kann sich niemals selbst blockieren. Siehe comment by @kgrittn below, der ein Experte für Parallelität in PostgreSQL ist.

Ihre Version von PostgreSQL fehlt. Moderne Versionen erhöhen eine detaillierte Fehlermeldung. Beide Prozesse, die um Ressourcen konkurrieren, werden detailliert mit Standardprotokolleinstellungen aufgeführt. Überprüfen Sie Ihre Datenbankprotokolle.

Die Tatsache, dass Sie den Fehler bemerken, kann Postgres davon abhalten, Ihnen die vollständigen Details zu geben. Entfernen Sie den EXCEPTION Block aus Ihrer plpgsql Funktion, wenn Sie die Information in dem Db-Protokoll nicht abrufen, und versuchen Sie es erneut.

Um Deadlocks zu vermeiden, können Sie eine Reihe von Dingen tun. Wenn alle Clients in einer synchronisierten Reihenfolge auf Ressourcen zugreifen, können keine Deadlocks auftreten. Das Handbuch bietet die grundlegende Strategie zur Lösung der meisten Fälle im Kapitel über deadlocks.


Was Version 8.3: Sehen Sie auf eine neuere Version zu aktualisieren. in den Stillstand zu dem Serverprotokoll (Itagaki Takahiro)

beteiligt

Bei der Meldung zu einem Deadlock, melden Sie den Text aller Anfragen: Insbesondere diese Verbesserung in der Version 8.4 sollte für Sie (quoting the release notes) interessant sein

Auch Version 8.3 erfüllt die end of life in February 2013. Sie sollten mit dem Upgrade beginnen.

Eine Deadlock-Situation mit VACUUM sollte fixed in 8.3.1 sein.

+0

Ich habe postgres 8.3.6. Diese Aussage verwenden Sie nur zum Beispiel. Tatsächlich benutze ich das Einfügeprotokoll zu einer anderen Tabelle statt RAISE NOTICE. –

+0

Normalerweise sollte die Fehlermeldung Ihnen die Informationen geben, die Sie benötigen. Ich fügte meiner Antwort ein wenig hinzu. –

+0

Vielen Dank für Ihren Rat. Ich werde weiterhin herausfinden, welche anderen Prozesse versuchen, etwas mit dieser Tabelle zu tun. –

-1

In PostgreSQL bedeutet begin, dass Sie die Batch-Transaktion starten.

Ihre erste Aktualisierung wird Zeilen für Konten sperren WHERE acct_name like 'A%'; Diese Zeilen sind exklusiv nach dem ersten Update gesperrt.

Das zweite Update versucht, genau die gleichen Zeilen wie das erste Update zu öffnen, um zu aktualisieren fehlgeschlagen, weil das erste Update noch nicht festgeschrieben wurde.

So war zweiten Update Hit Deadlock Rollback.

+0

In PL/pgSQL ist 'BEGIN' nur der Anfang eines Codeblocks. Nicht dasselbe wie 'BEGIN' /' COMMIT' in normalem SQL. –

0

Sie würden kein Deadlock-Problem bekommen, wenn Sie commit hinzufügen, um exklusive Sperren freizugeben.

BEGIN 
UPDATE accounts SET balance = 0 WHERE acct_name like 'A%'; 
COMMIT; 
UPDATE accounts SET balance = balance + 100 WHERE acct_name like '%A'; 
EXCEPTION WHEN OTHERS THEN RAISE NOTICE SQLERRM; 
END; 
+1

Prozedur in plpgsql im Einzeltransaktions-Commit-Block ausgeführt, also gibt es kein Commit innerhalb von Prozeduren. – sharafjaffri