Veuillez considérer le script suivant:
create or replace function f(p_limit in integer) return integer as
begin
set_global_context ('limit', p_limit);
return p_limit;
end;
/
create view v as
select level as val from dual connect by level<=sys_context('global_context','limit');
select f(2), v.* from v;
/*
F(2) VAL
---------------------- ----------------------
2 1
2 2
*/
select f(4), v.* from v;
/*
F(4) VAL
---------------------- ----------------------
4 1
4 2
4 3
4 4
*/
Puis-je compter sur l' f(x)
exécution avant la lecture du contexte dans la vue, comme cela a été le cas dans ce scénario de test exécuté sur 10.2?
SELECT stuff FROM dbo.FuncReturningTable(param)
ou similaire. Oracle a probablement des fonctionnalités équivalentes. Cependant, si j'utilise cela sur de grands ensembles de données, je ferais attention à surveiller les performances: je ne sais pas à quel point le planificateur de requêtes devrait être brillant pour faire un plan efficace à partir d'une telle syntaxe.Réponses:
Non.
Si vous réécrivez votre vue avec le filtrage de contexte par rapport à la clause where (au lieu de la connexion par), vous obtiendrez la valeur précédemment définie pour le contexte:
La clause where étant évaluée avant la sélection des colonnes, la valeur transmise à la fonction n'est définie qu'après la lecture du contexte. L'emplacement de l'appel sys_context dans votre requête (sélectionner, où, grouper par, etc.) affectera exactement le moment où cette valeur est définie.
la source
D'une manière générale, vous ne pouvez rien supposer de manière sûre de l'ordre dans lequel votre SGBD fera les choses lors de l'évaluation d'une seule instruction SQL. C'est pourquoi de nombreux SGBD n'autorisent pas les fonctions utilisées de cette façon à avoir des effets secondaires (c'est-à-dire que MSSQL ne permet pas aux fonctions de définir l'état global / de connexion, ce que vous faites là-bas, ou de modifier le contenu de la table). Une série d'instructions doit être exécutée d'une manière qui a du sens d'une étape à l'autre (c'est-à-dire qu'elles sont exécutées en série, ou de telle manière que vous ne pouvez pas dire qu'elles ne l'ont pas été), mais dans une seule instruction, le planificateur de requêtes a le règne libre tant qu'il n'introduit pas d'ambiguïté là où il n'existe pas déjà (dans votre exemple, l'ambiguïté existe déjà parce que la fonction a un effet secondaire affecte la vue).
Si le planificateur de requêtes était suffisamment lumineux pour détecter que la vue est affectée par les effets secondaires de la fonction, que ferait-il si vous rejoigniez une autre vue qui appelait potentiellement cette fonction avec différentes valeurs d'entrée? Cela pourrait très rapidement devenir très poilu - ce genre de chose est pourquoi généralement, dans n'importe quel contexte de programmation, les fonctions ne devraient pas avoir d'effets au-delà de leur propre sortie.
Dans cet exemple spécifique, je dirais qu'il est peu probable que f (x) soit appelé en premier, car c'est dans la partie "affichage" de l'instruction: le jeu de résultats de la vue est susceptible d'être récupéré avant toute fonction dans le la liste des colonnes à renvoyer est évaluée. Bien sûr, cela variera en fonction du SGBD utilisé: je ne suis pas un expert Oracle et vos résultats de test montrent que la fonction semble être appelée en premier dans ces cas. Mais je me méfierais de compter sur l'ordre d'exécution dans une seule instruction SQL tout de même - même si cela fonctionne toujours comme vous vous attendez en ce moment, il se peut qu'il ne le fasse pas dans les futures révisions (à moins qu'il ne soit officiellement documenté quelque part que l'exécution se déroulera toujours de cette façon).
la source
La documentation promet seulement que "L'optimiseur évalue d'abord les expressions et les conditions contenant des constantes aussi complètement que possible." ( 10.2 , 11.2 ). Vous n'êtes pas assuré qu'il évaluera d'abord une expression particulière ou qu'il ne changera pas cet ordre de temps en temps (un nouveau niveau de patch dans la même version?).
la source