PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

L'union postgres garantit-elle l'ordre d'exécution lors de l'appel de fonctions avec des effets secondaires ?

En pratique, ils seront exécutés dans l'ordre indiqué, mais il n'y a aucune garantie.

Si c'est garanti, cela sera couvert dans la documentation ou dans le standard SQL. Je ne vois aucune mention d'ordre d'exécution d'un UNION dans l'un ou l'autre.

Si l'optimiseur avait une raison d'exécuter l'un avant l'autre, il serait libre de le faire.

Pour garantir l'ordre d'exécution, exécutez les instructions dans l'ordre souhaité :

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

Si vous souhaitez réduire les allers-retours, utilisez si possible les installations de traitement par lots de votre client ou utilisez un DO bloquer :

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

Si vous devez renvoyer des valeurs, utilisez une fonction et RETURN QUERY ou RETURN NEXT .

Ou vous pouvez forcer la commande avec un CTE, car dans PostgreSQL (malheureusement) CTE agissent comme des barrières d'optimisation qui forcent la matérialisation des résultats . Cependant, AFAIK PostgreSQL n'a toujours pas à exécuter les termes CTE dans l'ordre dans lequel ils sont écrits ou dans l'ordre dans lequel ils sont référencés ; la seule garantie que vous obtenez est si vous faites ceci :

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

puis function1 doit être exécuté et matérialisé en premier. C'est cependant une mauvaise fonctionnalité spécifique à PostgreSQL ; ce n'est pas le cas des autres moteurs de base de données, non garantis par la norme, et vous ne devriez pas vous y fier.

Cela ne s'étend pas à

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

... comme dans ce cas, PostgreSQL peut exécuter les termes CTE indépendants dans l'un ou l'autre ordre.

Encore une fois, avec les jointures, le même principe s'applique. Si les termes sont indépendants, le système peut choisir de les exécuter dans n'importe quel ordre, bien qu'il ne le fasse généralement pas. Donc :

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

pourrait évaluer et matérialiser bar() puis joignez ses résultats sur foo() .

Si vous souhaitez une exécution ordonnée, vous ne devriez pas vous fier aux opérations d'ensemble telles que les unions et les jointures. Utilisez des requêtes distinctes ou un code procédural.

Oui, il y en a.

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