SELECT FOR UPDATE/SHARE ist nicht mit Aggregatfunktionen erlaubt

Hallo,

ich bin heute auf diesen Fehler bei einer SQL-Abfrage gestoßen:

SELECT FOR UPDATE/SHARE ist nicht mit Aggregatfunktionen erlaubt

Diese konkrete Abfrage könnte ich zwar mit viel Aufwand so umschreiben, dass sie Sequences statt SELECT MAX(…) FOR UPDATE verwendet, aber an anderen Stellen sind Sequences keine Lösung. Überhaupt, Aggregatfunktionen mit FOR UPDATE funktioniert in anderen Datenbanksystemen wunderbar und hat auch in PostgreSQL 8.2 noch funktioniert. Dass es nun verboten ist, habe ich in der aktuellen Doku nachlesen können. Warum geht das jetzt nicht mehr? Welche Alternativen sind dafür vorgesehen? Muss ich mit LOCK TABLE die Tabelle sperren, falls das überhaupt unterstützt wird? Es gibt eben einfach Momente, in denen andere eine Tabelle nicht anfassen dürfen.

Welche Row sollte den gelockt werden?
Eine Aggregatsfunktion mach aus vielen Rows eine Row. Den resultierenden Datensatz gibt es in der Tabelle gar nicht. Was also soll denn gelockt werden?

“select max(…) … for update” sperrt, soweit ich das verstanden habe, in MySQL den Index nach dem letzten Eintrag. So kann niemand in der Zwischenzeit kommen und einen neuen max(…) anlegen. Gut, dafür könnte man Sequences verwenden (die es in MySQL wiederum nicht gibt). Aber auch das kann man ja alles abstrahieren.

"select count() … for update" sperrt, soweit ich das verstanden habe, die ganze Tabelle, so dass niemand mein count() verändern kann. Das ist wichtig, weil ich abhängig davon, ob count 0 ergibt, einen anderen Wert woanders löschen muss. Wenn währenddessen jemand count wieder erhöht (durch Einfügen von Zeilen), dann geht was kaputt. Fremdschlüssel sind hier nicht anwendbar, sonst hätte ich das gemacht.

Kann ich die Tabelle mit LOCK TABLE oder sowas sperren?

wieso macht man ein “SELECT COUNT(*)”? Das frisst ja ohne Ende Performance!

Und ja, du kannst “LOCK” verwenden. Der Befehl ist in der Dokumentation erklärt.

Ja.

Andreas

Umm, also bislang ging das immer recht fix. Kann natürlich sein, dass es speziell in PostgreSQL langsam ist. Wie finde ich dann raus, wie viele Zeilen eine Tabelle hat, die einer bestimmten Bedingung genügen? Oder im Sonderfall, ob es überhaupt welche gibt?

Jein. Bei kleinen Tabellen ist es relativ egal, aber es bewirkt in jedem Fall einen Seq-Scan der Tabelle.

Wie finde ich dann raus, wie viele Zeilen eine Tabelle hat, die einer bestimmten Bedingung genügen? Oder im Sonderfall, ob es überhaupt welche gibt?

FAQ - PostgreSQL Wiki

Andreas