PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Garantiert Postgres Union die Ausführungsreihenfolge beim Aufrufen von Funktionen mit Nebeneffekten?

In der Praxis werden sie in der angegebenen Reihenfolge ausgeführt, es wird jedoch keine Garantie übernommen.

Wenn es garantiert ist, wird es in der Dokumentation oder im SQL-Standard behandelt. Ich sehe keine Erwähnung der Ausführungsreihenfolge einer UNION in beiden.

Wenn der Optimierer einen Grund hätte, einen vor dem anderen auszuführen, wäre er frei, dies zu tun.

Um die Ausführungsreihenfolge sicherzustellen, führen Sie Anweisungen in der gewünschten Reihenfolge aus:

SELECT * FROM func1();
SELECT * FROM func2();

Wenn Sie Roundtrips reduzieren möchten, verwenden Sie nach Möglichkeit die Batching-Einrichtungen Ihres Kunden oder verwenden Sie ein DO blockieren:

DO
$$
BEGIN
  PERFORM proc1();
  PERFORM proc2();
END;
$$;

Wenn Sie Werte zurückgeben müssen, verwenden Sie eine Funktion und RETURN QUERY oder RETURN NEXT .

Oder Sie können die Bestellung mit einem CTE erzwingen, weil in PostgreSQL (leider) CTEs fungieren als Optimierungszäune, die die Materialisierung von Ergebnissen erzwingen . AFAIK PostgreSQL muss die CTE-Begriffe jedoch immer noch nicht in der Reihenfolge ausführen, in der sie geschrieben sind, oder in der Reihenfolge, in der sie referenziert werden. Die einzige Garantie, die Sie erhalten, ist, wenn Sie dies tun:

WITH f1 AS (SELECT * FROM function1())
SELECT * FROM function2()
UNION ALL
SELECT * FROM f1;

dann function1 müssen zuerst ausgeführt und materialisiert werden. Das ist jedoch eine PostgreSQL-spezifische Fehlfunktion; es gilt nicht für andere Datenbank-Engines, die nicht vom Standard garantiert werden, und Sie sollten sich nicht darauf verlassen.

Das gilt nicht für

WITH f1 AS (SELECT * FROM function1())
     f2 AS (SELECT * FROM function2())
SELECT * FROM f2
UNION ALL
SELECT * FROM f1;

... da PostgreSQL in diesem Fall die unabhängigen CTE-Terme in beliebiger Reihenfolge ausführen kann.

Auch bei Joins gilt das gleiche Prinzip. Wenn die Begriffe unabhängig sind, kann das System sie in beliebiger Reihenfolge ausführen, obwohl dies im Allgemeinen nicht der Fall ist. Also:

select null::void from (select 1 from foo() ) left join (select 1 from bar()) on true

könnte bar() auswerten und materialisieren dann verbinden Sie die Ergebnisse mit foo() .

Wenn Sie eine geordnete Ausführung wünschen, sollten Sie sich nicht auf Mengenoperationen wie Unions und Joins verlassen. Verwenden Sie separate Abfragen oder Verfahrenscode.

Ja, das gibt es.

SELECT * FROM function1();
SELECT * FROM function2();