PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Postgres union garantisce l'ordine di esecuzione quando si richiamano funzioni con effetti collaterali?

In pratica verranno eseguiti nell'ordine impartito, ma non viene fornita alcuna garanzia.

Se è garantito, sarà trattato nella documentazione o nello standard SQL. Non vedo alcuna menzione dell'ordine di esecuzione di un UNION in entrambi.

Se l'ottimizzatore avesse un motivo per eseguirne uno prima dell'altro, sarebbe libero di farlo.

Per garantire l'ordine di esecuzione, esegui le istruzioni nell'ordine desiderato:

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

Se desideri ridurre i viaggi di andata e ritorno, utilizza le strutture di batching del tuo cliente, se possibile, oppure utilizza un DO blocco:

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

Se devi restituire dei valori, usa una funzione e RETURN QUERY o RETURN NEXT .

Oppure puoi forzare l'ordine con un CTE, perché in PostgreSQL (purtroppo) i CTE agiscono come barriere di ottimizzazione che forzano la materializzazione dei risultati . Tuttavia, AFAIK PostgreSQL non deve ancora eseguire i termini CTE nell'ordine in cui sono scritti o nell'ordine in cui sono referenziati; l'unica garanzia che ottieni è se lo fai:

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

quindi function1 deve essere prima eseguito e materializzato. Tuttavia, questa è una funzionalità errata specifica di PostgreSQL; non è vero per altri motori di database, non è garantito dallo standard, e non dovresti fare affidamento su di esso.

Ciò non si estende a

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

... poiché in questo caso PostgreSQL può eseguire i termini CTE indipendenti in entrambi gli ordini.

Anche in questo caso, con i join, si applica lo stesso principio. Se i termini sono indipendenti, il sistema può scegliere di eseguirli in qualsiasi ordine, anche se generalmente non lo farà. Quindi:

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

potrebbe valutare e materializzare bar() quindi unisci i suoi risultati su foo() .

Se desideri un'esecuzione ordinata, non dovresti fare affidamento su operazioni sugli insiemi come unioni e join. Utilizza query separate o codice procedurale.

Sì, c'è.

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