Posso confiar nas funções que estão sendo executadas primeiro no SQL

9

Por favor, considere o seguinte 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                      
*/

Posso confiar em f(x)ser executado antes que o contexto seja lido dentro da visualização, como foi neste caso de teste executado na 10.2?

Jack diz que tenta topanswers.xyz
fonte
Não ajuda, mas pode pensar um gatilho de login pode ser mais apropriado (se o nível será sempre o mesmo, que é)
Philᵀᴹ
@ Phil, este é apenas um exemplo - estou usando sys_context para parametrizar uma exibição e o parâmetro será diferente a cada vez. Se você souber uma maneira de definir um contexto global a partir do SQL sem mexer com isso, também estaria interessado em ouvir isso!
Jack diz que tente topanswers.xyz
11
@JackDouglas: avaliar um parâmetro é uma ideia que não "parece" certa para mim. No MSSQL, o que você está tentando fazer pode ser feito usando uma função definida pelo usuário que retorna um conjunto de resultados (em vez de um valor), - você pode então SELECT stuff FROM dbo.FuncReturningTable(param)ou similar. O Oracle provavelmente tem funcionalidade equivalente. Embora, se você usar isso em grandes conjuntos de dados, tenha cuidado para monitorar o desempenho: não tenho certeza de quão brilhante o planejador de consultas precisaria para criar um plano eficiente a partir dessa sintaxe.
David Spillett 29/07
A definição de parâmetros para David é geralmente feita com sys_context - normalmente você definiria o contexto antes de executar a consulta (por exemplo, com um pouco de PL / SQL). A Oracle possui funções de retorno de conjunto e / ou em pipeline, mas elas não são a maneira 'normal' de conseguir isso. Para ser claro, acho que a resposta para a pergunta no título é "não" - eu apenas me perguntei se alguém sabia melhor.
Jack diz que tente topanswers.xyz

Respostas:

8

Não.

Se você reescrever sua visualização com a filtragem de contexto na cláusula where (em vez da conexão por), obterá o valor definido anteriormente para o 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 a cláusula where é avaliada antes da seleção das colunas, o valor passado para a função não é definido até depois da leitura do contexto. O local da chamada sys_context na sua consulta (selecione onde, agrupar por etc.) afetará exatamente quando esse valor for definido.

Chris Saxon
fonte
O +1 é praticamente "caso encerrado" no meu livro, obrigado.
Jack diz que tente topanswers.xyz
2

De um modo geral, você não pode assumir com segurança nada sobre a ordem em que o DBMS fará as coisas ao avaliar uma única instrução SQL. É por isso que muitos DBMS não permitem que as funções usadas dessa maneira tenham efeitos colaterais (ou seja, o MSSQL não permite que as funções definam o estado global / de conexão que você está fazendo lá ou altere o conteúdo da tabela). Uma série de instruções deve ser executada de uma maneira que faça sentido de uma etapa para a seguinte (ou seja, elas são executadas em série ou da maneira que você não pode dizer que não foram), mas em uma única instrução o planejador de consultas tem domínio livre, desde que não introduza ambiguidade onde ainda não existe (no seu exemplo, ambiguidade já existe porque a função tem um efeito colateral afeta a exibição).

Se o planejador de consultas estivesse brilhante o suficiente para detectar que a exibição é afetada pelos efeitos colaterais da função, o que faria se você ingressasse em outra exibição que chamasse essa função potencialmente com diferentes valores de entrada? Ele pode ficar muito peludo rapidamente - esse tipo de coisa é porque geralmente, em qualquer contexto de programação, as funções não devem ter efeitos além de sua própria saída.

Neste exemplo específico, eu diria que é improvável que f (x) seja chamado primeiro, pois ele "exibe" parte da instrução: é provável que o conjunto de resultados da visualização seja recuperado antes de qualquer função dentro do lista de colunas a retornar são avaliadas. É claro que isso varia de acordo com o DBMS usado: eu não sou especialista em Oracle e os resultados de seus testes mostram que a função parece ser chamada primeiro nessas instâncias. Mas eu seria cauteloso em confiar na ordem de execução em qualquer instrução SQL da mesma forma - mesmo que sempre funcione da maneira que você espera no momento, pode não fazê-lo em futuras revisões (a menos que esteja oficialmente documentado em algum lugar em que a execução sempre será executada) desta maneira).

David Spillett
fonte
2
Boa resposta, mas sinto que Jack está procurando uma resposta técnica definitiva do Oracle.
`` #
1

A documentação promete apenas que "o otimizador primeiro avalia expressões e condições contendo constantes o mais completamente possível". ( 10,2 , 11,2 ). Você não tem garantia de que ele avaliará primeiro qualquer expressão específica ou que não mudará essa ordem de tempos em tempos (um novo nível de patch na mesma versão?).

Stephen Kendall
fonte
+1 excelente, obrigado (apesar de ler esses documentos não
coincidir
11
A diferença é se a função é chamada na cláusula where, select ou em alguma outra cláusula. As funções na seção de seleção não afetam as decisões do otimizador (a menos que seja uma subconsulta); portanto, elas não precisam ser avaliadas até a busca dos resultados. As funções na cláusula where afetarão o método de junção usado, portanto, precisam ser avaliadas o mais rápido possível.
31512 Chris Saxon
@ Chris é essa experiência falando ou você conseguiu isso nos documentos em algum lugar?
Jack diz que tente topanswers.xyz
Não consigo encontrar uma referência de documento. Com base na minha experiência, se for chamada na cláusula where para filtrar uma única tabela, ela será acessada para cada linha (assumindo um STF), mas apenas para as linhas retornadas se na lista de seleção. Como o plano de execução é definido durante a análise, isso implica que as funções em select não podem afetá-lo. Um caso de teste para verificar isso pode ser feito criando uma função configurando um contador (em um pacote ou tabela) e comparando a saída com base em onde a consulta é colocada.
31412 Chris