Pergunta

Digamos que eu tenho uma chamada de função em um selecione ou onde cláusula no Oracle como esta:

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

Um exemplo semelhante pode ser construído para o MS SQL Server.

O que é o comportamento esperado em cada caso?

O HASH função vai ser chamado uma vez para cada linha na tabela, ou DBMS será suficiente inteligente para chamar a função apenas uma vez, já que é uma função com parâmetros constantes e nenhum efeitos colaterais ?

Muito obrigado.

Foi útil?

Solução

A resposta para Oracle é que depende. A função será chamada para cada linha selecionada menos que a função é marcada 'determinística' caso em que ela só vai ser chamado uma 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;

Output:

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

3 rows selected


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

1 rows selected

Assim, a função StringLen () foi chamado três vezes no primeiro caso. Agora, quando executar com StringLen2 (), que é denotada 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;

Resultado:

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

3 rows selected

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

1 rows selected

Assim, a função StringLen2 () só foi chamado uma vez desde que foi marcada determinista.

Para uma função não marcado determinista, você pode contornar este problema, modificando sua 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
);

Outras dicas

Para o servidor SQL, ele será avaliado para cada linha.

Você vai ser muito melhor, executando a função uma vez e atribuir a uma variável e usar a variável na consulta.

resposta curta .... ele depende.

Se a função está acessando dados Oracle não sabe se ele vai ser o mesmo para cada linha, portanto, ele precisa de consulta para cada um. Se, por exemplo, a sua função é apenas um formatador que sempre retorna o mesmo valor, então você pode ativar o cache (marcando-o como determinística) que pode permitir que você só para fazer a chamada de função uma vez.

Algo que você pode querer olhar é ORACLE COM subconsulta:

A cláusula query_name COM permite atribuir um nome a um bloco de subconsulta. Vocês pode, em seguida, referência o bloco subconsulta vários lugares na consulta por especificando o nome da consulta. Oráculo otimiza a consulta tratando o nome da consulta ou como uma visão em linha ou como uma tabela temporária

Eu tenho o texto citado de aqui , que tem abundância de exemplos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top