¿Puedo confiar en que las funciones se ejecuten primero en SQL

9

Por favor considere el siguiente script:

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                      
*/

¿Puedo confiar en que f(x)se ejecute antes de que se lea el contexto dentro de la vista, como se ha ejecutado en este caso de prueba en 10.2?

Jack dice que intente topanswers.xyz
fuente
No puedo evitar pensar que un disparador de inicio de sesión podría ser más apropiado (si el nivel siempre será el mismo, eso es)
Phil
@ Phil esto es solo un ejemplo: estoy usando sys_context para parametrizar una vista y el parámetro será diferente cada vez. Si conoces una manera de establecer un contexto global desde SQL sin perder el tiempo de esta manera, ¡también me interesaría escuchar eso!
Jack dice que intente topanswers.xyz
1
@JackDouglas: la parametrización de una vista es una idea que no me parece "correcta". En MSSQL, lo que está tratando de hacer podría hacerse utilizando una función definida por el usuario que devuelva un conjunto de resultados (en lugar de un valor), puede hacerlo SELECT stuff FROM dbo.FuncReturningTable(param)o similar. Oracle probablemente tiene una funcionalidad equivalente. Sin embargo, si uso esto en grandes conjuntos de datos, tendré cuidado de monitorear el rendimiento: no estoy seguro de cuán brillante debería ser el planificador de consultas para hacer un plan eficiente a partir de dicha sintaxis.
David Spillett
@David parateraterizar una vista se realiza comúnmente con sys_context, solo que normalmente establecería el contexto antes de ejecutar la consulta (por ejemplo, con un poco de PL / SQL). Oracle tiene funciones de retorno de conjunto y / o canalizadas, pero no son la forma "normal" de lograr esto. Para ser claros, creo que la respuesta a la pregunta en el título es "no". Me preguntaba si alguien lo sabía mejor.
Jack dice que intente topanswers.xyz

Respuestas:

8

No.

Si reescribe su vista con el filtro de contexto contra la cláusula where (en lugar de conectar por), obtendrá el valor establecido previamente para el contexto:

create table t as 
 select rownum r from dual connect by level <= 10;

create or replace view v as 
  select r val from t where r <=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 

select f(4), v.* from v;

F(4) VAL
---- ---
   4   1 
   4   2 
   4   3 
   4   4 

Como la cláusula where se evalúa antes de que se seleccionen las columnas, el valor pasado a la función no se establece hasta después de leer el contexto. La ubicación de la llamada sys_context en su consulta (seleccionar, dónde, agrupar por, etc.) afectará exactamente cuando se establece este valor.

Chris Saxon
fuente
+1 es más o menos "caso cerrado" en mi libro, gracias.
Jack dice que intente topanswers.xyz
2

En términos generales, no puede asumir con seguridad nada sobre el orden en que su DBMS hará las cosas al evaluar una sola instrucción SQL. Esta es la razón por la cual muchos DBMS no permitirán que las funciones utilizadas de esa manera tengan efectos secundarios (es decir, MSSQL no permitirá que las funciones establezcan el estado global / conexión, lo que está haciendo allí, o altere el contenido de la tabla). Una serie de declaraciones debe ejecutarse de una manera que tenga sentido de un paso al siguiente (es decir, se ejecutan en serie o de una manera que no se puede decir que no lo fueron), pero dentro de una sola declaración el planificador de consultas tiene un reinado libre siempre que no introduzca ambigüedad donde no existe (en su ejemplo, la ambigüedad ya existe porque la función tiene un efecto secundario que afecta la vista).

Si el planificador de consultas fuera lo suficientemente brillante como para detectar que la vista se ve afectada por los efectos secundarios de la función, ¿qué haría si se uniera a otra vista que llamara a esa función potencialmente con diferentes valores de entrada? Podría volverse muy peludo rápidamente: este tipo de cosas es la razón por la cual, en general, en cualquier contexto de programación, las funciones no deberían tener efectos más allá de su propia salida.

En este ejemplo específico, diría que es poco probable que se llame primero a f (x), ya que es "parte" de la declaración: es probable que el conjunto de resultados de la vista se recupere antes de cualquier función dentro del Se evalúa la lista de columnas a devolver. Por supuesto, esto variará según el DBMS utilizado: no soy un experto en Oracle y los resultados de su prueba muestran que la función parece llamarse primero en estos casos. Pero sería cauteloso de depender del orden de ejecución dentro de una sola instrucción SQL de todos modos, incluso si siempre funciona de la manera esperada en este momento, puede que no lo haga en futuras revisiones (a menos que esté documentado oficialmente en algún lugar que la ejecución siempre irá por aquí)

David Spillett
fuente
2
Buena respuesta, pero siento que Jack está buscando una respuesta técnica definitiva de Oracle.
Philᵀᴹ
1

La documentación solo promete que "El optimizador primero evalúa las expresiones y condiciones que contienen constantes de la forma más completa posible". ( 10.2 , 11.2 ). No se garantiza que primero evaluará ninguna expresión en particular, o que no cambiará ese orden de vez en cuando (¿un nuevo parche en el mismo lanzamiento?).

Stephen Kendall
fuente
+1 excelente, gracias (aunque a mi lectura esos documentos no
coinciden
1
La diferencia es si la función se llama en where, select o alguna otra cláusula. Las funciones en la sección de selección no afectarán las decisiones del optimizador (a menos que sea una subconsulta), por lo que no es necesario evaluarlas hasta obtener los resultados. Sin embargo, las funciones en la cláusula where afectarán el método de unión utilizado, por lo que deben evaluarse lo más pronto posible.
Chris Saxon
@Chris, ¿es esa experiencia hablar o la obtuviste de los documentos en alguna parte?
Jack dice que intente topanswers.xyz
No puedo encontrar una referencia de documento. Según mi experiencia, si se llama en la cláusula where para filtrar una sola tabla, se accederá a cada fila (suponiendo un FTS), pero solo para las filas devueltas si están en la lista de selección. Como el plan de ejecución se establece durante el análisis, esto implica que las funciones en select no pueden afectarlo. Un caso de prueba para verificar esto podría hacerse creando una función que establezca un contador (en un paquete o tabla) y comparando el resultado en función de en qué parte de la consulta se coloca.
Chris Saxon