inicio mail me! sindicaci;ón

Atomares Einfügen in PostgreSQL | Teil 2

Die im vorletzten Artikel vorgestellte Lösung hat den Nachteil, den ganzen Table my_table zu locken.
Das ist dann ein Problem, wenn criterion mittels unique constraint eindeutig gemacht wird und nach der Funktion eine zeitaufwendige Funktion (z.B. eine Suche) in derselben Transaktion folgt: Dann warten nämlich alle Prozesse, die ein findOrCreate machen wollen, unabhängig mit welchem Wert für criterion, auf den Abschluss der ersten Transaktion, da erst zu diesem Zeitpunkt sichergestellt werden kann, dass die Spalte wirklich unique ist.

Eigentlich sollte es aber möglich sein, dass parallele Transaktionen mit anderen Werten für criterion unbehelligt ausgeführt werden.
Mit dem folgenden, von Martin Heistermann und Stephan Lüderitz vorgeschlagenen Ansatz, umgeht man dieses Problem elegant:

CREATE OR REPLACE FUNCTION findOrCreate(
  IN criterion_in text,
  OUT record_id integer, OUT is_new bool) AS
$$
DECLARE
BEGIN
    INSERT INTO
      my_table (criterion)
    VALUES
      (criterion_in)
    RETURNING id INTO record_id;
    SELECT true INTO is_new;
EXCEPTION
    WHEN unique_violation THEN
        SELECT false, id into is_new, record_id FROM my_table 
        WHERE criterion=criterion_in;
END
$$ language plpgsql;

Wie in dieser Präsentation (PDF) beschrieben, läßt PostgreSQL das parallele Einfügen verschiedener Werte mittels findOrCreate zu, zwingt aber bei zwei Transaktionen, die denselben Wert einfügen wollen, die zweite, mit dem Insert auf das Ende der ersten zu warten.

Findet die (potentiell teure) Suche in der Transaktion nach findOrCreate statt, wird diese gar nicht mehr ausgeführt, da findOrCreate per Exception die von der ersten Transaktion neu eingefügte Zeile ermittelt und gleich mit deren Ergebnissen weitermachen kann.

Schreibe einen Kommentar