Pregunta

Digamos que tengo una llamada de función en una selección o donde cláusula en Oracle como esta:

select a, b, c, dbms_crypto.hash(utl_raw.cast_to_raw('HELLO'),3)
  from my_table

Se puede construir un ejemplo similar para MS SQLServer.

¿Cuál es el comportamiento esperado en cada caso?

¿La función HASH se llamará una vez para cada fila de la tabla, o DBMS será lo suficientemente inteligente como para llamar a la función solo una vez, ya que es una función con parámetros constantes y sin efectos secundarios ?

Muchas gracias.

¿Fue útil?

Solución

La respuesta para Oracle es que depende. Se llamará a la función para cada fila seleccionada A MENOS que la función esté marcada como 'Determinista', en cuyo caso solo se llamará una vez.

CREATE OR REPLACE PACKAGE TestCallCount AS
    FUNCTION StringLen(SrcStr VARCHAR) RETURN INTEGER;
    FUNCTION StringLen2(SrcStr VARCHAR) RETURN INTEGER DETERMINISTIC;
    FUNCTION GetCallCount RETURN INTEGER;
    FUNCTION GetCallCount2 RETURN INTEGER;
END TestCallCount;

CREATE OR REPLACE PACKAGE BODY TestCallCount AS
    TotalFunctionCalls INTEGER := 0;
    TotalFunctionCalls2 INTEGER := 0;

    FUNCTION StringLen(SrcStr VARCHAR) RETURN INTEGER AS
    BEGIN
        TotalFunctionCalls := TotalFunctionCalls + 1;
        RETURN Length(SrcStr);
    END;
    FUNCTION GetCallCount RETURN INTEGER AS
    BEGIN
        RETURN TotalFunctionCalls;
    END;

    FUNCTION StringLen2(SrcStr VARCHAR) RETURN INTEGER DETERMINISTIC AS
    BEGIN
        TotalFunctionCalls2 := TotalFunctionCalls2 + 1;
        RETURN Length(SrcStr);
    END;
    FUNCTION GetCallCount2 RETURN INTEGER AS
    BEGIN
        RETURN TotalFunctionCalls2;
    END;

END TestCallCount;




SELECT a,TestCallCount.StringLen('foo') FROM(
    SELECT 0 as a FROM dual
    UNION
    SELECT 1 as a FROM dual
    UNION
    SELECT 2 as a FROM dual
);

SELECT TestCallCount.GetCallCount() AS TotalFunctionCalls FROM dual;

Salida:

A                      TESTCALLCOUNT.STRINGLEN('FOO') 
---------------------- ------------------------------ 
0                      3                              
1                      3                              
2                      3                              

3 rows selected


TOTALFUNCTIONCALLS     
---------------------- 
3                      

1 rows selected

Entonces, la función StringLen () se llamó tres veces en el primer caso. Ahora cuando se ejecuta con StringLen2 () que se denota determinista:

SELECT a,TestCallCount.StringLen2('foo') from(
    select 0 as a from dual
    union
    select 1 as a from dual
    union
    select 2 as a from dual
);

SELECT TestCallCount.GetCallCount2() AS TotalFunctionCalls FROM dual;

Resultados:

A                      TESTCALLCOUNT.STRINGLEN2('FOO') 
---------------------- ------------------------------- 
0                      3                               
1                      3                               
2                      3                               

3 rows selected

TOTALFUNCTIONCALLS     
---------------------- 
1                      

1 rows selected

Entonces, la función StringLen2 () solo se llamó una vez, ya que se marcó como determinista.

Para una función no marcada como determinista, puede evitar esto modificando su consulta como tal:

select a, b, c, hashed
  from my_table
cross join (
  select dbms_crypto.hash(utl_raw.cast_to_raw('HELLO'),3) as hashed from dual
);

Otros consejos

Para el servidor SQL, se evaluará para cada fila individual.

Será mucho mejor ejecutando la función una vez y asignándola a una variable y utilizando la variable en la consulta.

respuesta corta ... depende.

Si la función está accediendo a los datos, ORACLE no sabe si va a ser el mismo para cada fila, por lo tanto, necesita consultar cada una. Si, por ejemplo, su función es solo un formateador que siempre devuelve el mismo valor, puede activar el almacenamiento en caché (marcándolo como determinista), lo que puede permitirle hacer solo la llamada a la función una vez.

Algo que tal vez desee analizar es ORACLE WITH subquery:

  

La cláusula WITH query_name te permite   asignar un nombre a un bloque de subconsulta. usted   puede hacer referencia al bloque de subconsulta   múltiples lugares en la consulta por   especificando el nombre de la consulta. Oráculo   optimiza la consulta tratando el   nombre de la consulta como una vista en línea o   como una tabla temporal

Obtuve el texto citado de aquí , que tiene muchos ejemplos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top