Posso fare affidamento sulle funzioni eseguite per prime in SQL


9

Si prega di considerare il seguente 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 fare affidamento sull'esecuzione f(x)prima che il contesto venga letto all'interno della vista, come è stato in questo caso test eseguito su 10.2?


Non posso fare a meno di pensare che un trigger di accesso potrebbe essere più appropriato (se il livello sarà sempre lo stesso, cioè)
Phil,

@Phil questo è solo un esempio - sto usando sys_context per parametrizzare una vista e il parametro sarà diverso ogni volta. Se conosci un modo per impostare un contesto globale da SQL senza fare confusione in questo modo, sarei anche interessato a sentirlo!
Jack dice di provare topanswers.xyz il

1
@JackDouglas: parametrizzare una vista è un'idea che non "mi sembra" giusta per me. In MSSQL ciò che si sta tentando di fare potrebbe essere fatto utilizzando una funzione definita dall'utente che restituisce un gruppo di risultati (anziché un valore), quindi è possibile SELECT stuff FROM dbo.FuncReturningTable(param)o simile. Oracle ha probabilmente funzionalità equivalenti. Tuttavia, se lo utilizzassi su insiemi di dati di grandi dimensioni, farei attenzione a monitorare le prestazioni: non sono sicuro di quanto sia necessario il pianificatore di query per creare un piano efficiente da tale sintassi.
David Spillett,

@David la parametrizzazione di una vista viene generalmente eseguita con sys_context - normalmente si imposta il contesto prima di eseguire la query (ad es. Con un po 'di PL / SQL). Oracle ha funzioni di restituzione e / o pipeline, ma non sono il modo "normale" per raggiungere questo obiettivo. Per essere chiari, penso che la risposta alla domanda nel titolo sia "no" - mi chiedevo solo se qualcuno lo sapesse meglio.
Jack dice di provare topanswers.xyz il

Risposte:


8

No.

Se riscrivi la tua vista con il filtro di contesto rispetto alla clausola where (anziché la connessione per), otterrai il valore precedentemente impostato per il contesto:

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 

Poiché la clausola where viene valutata prima della selezione delle colonne, il valore passato alla funzione non viene impostato fino a quando non viene letto il contesto. La posizione della chiamata sys_context nella query (seleziona, dove, raggruppa per, ecc.) Influirà esattamente quando questo valore è impostato.


+1 è praticamente "caso chiuso" nel mio libro, grazie.
Jack dice di provare topanswers.xyz il

2

In generale, non puoi assumere in modo sicuro nulla sull'ordine in cui il tuo DBMS farà le cose quando valuta una singola istruzione SQL. Questo è il motivo per cui molti DBMS non consentiranno alle funzioni utilizzate in quel modo di avere effetti collaterali (cioè MSSQL non consentirà alle funzioni di impostare lo stato globale / di connessione, che si sta facendo lì, o alterare il contenuto della tabella). Una serie di istruzioni deve essere eseguita in modo sensato da un passaggio all'altro (ovvero vengono eseguite in serie o in modo da non poter dire che non lo sono), ma all'interno di una singola istruzione il pianificatore di query ha il regno libero fintanto che non introduce ambiguità dove non esiste già (nel tuo esempio l'ambiguità esiste già perché la funzione ha un effetto collaterale sulla vista).

Se il pianificatore di query fosse sufficientemente luminoso da rilevare che la vista è influenzata dagli effetti collaterali della funzione, cosa farebbe se si unisse in un'altra vista che chiamava quella funzione potenzialmente con valori di input diversi? Potrebbe rapidamente diventare molto peloso: questo genere di cose è il motivo per cui generalmente, in qualsiasi contesto di programmazione, le funzioni non dovrebbero avere effetti al di là del proprio output.

In questo esempio specifico direi che è improbabile che f (x) venga chiamato per primo, poiché è int che "visualizza" parte dell'istruzione: è probabile che il set di risultati dalla vista venga recuperato prima di qualsiasi funzione all'interno del viene valutato l'elenco delle colonne da restituire. Naturalmente questo varierà a seconda del DBMS utilizzato: non sono un esperto Oracle e i risultati dei test mostrano che la funzione sembra essere chiamata per prima in questi casi. Ma diffiderei di fare affidamento sull'ordine di esecuzione all'interno di ogni singola istruzione SQL lo stesso - anche se funziona sempre come previsto in questo momento potrebbe non farlo nelle revisioni future (a meno che non sia documentato ufficialmente da qualche parte che l'esecuzione andrà sempre in questo modo).


2
Buona risposta, ma sento che Jack sta cercando una risposta tecnica Oracle definitiva.
Philᵀᴹ

1

La documentazione promette solo che "L'ottimizzatore valuta innanzitutto le espressioni e le condizioni contenenti costanti nel modo più completo possibile". ( 10.2 , 11.2 ). Non hai la garanzia che valuterà prima una determinata espressione o che non cambierà di tanto in tanto tale ordine (un nuovo livello di patch all'interno della stessa versione?).


+1 eccellente, grazie (anche se alla mia lettura quei documenti non si
allineano

1
La differenza è se la funzione viene chiamata nella clausola where, select o in qualche altra clausola. Le funzioni nella sezione di selezione non influiranno sulle decisioni dell'ottimizzatore (a meno che non si tratti di una sottoquery), quindi non è necessario valutarle fino al recupero dei risultati. Le funzioni nella clausola where influenzeranno il metodo di join utilizzato, quindi devono essere valutate il più presto possibile.
Chris Saxon,

@Chris è quell'esperienza parlare o l'hai ottenuta dai documenti da qualche parte?
Jack dice di provare topanswers.xyz il

Non riesco a trovare un riferimento al documento. In base alla mia esperienza, se chiamato nella clausola where per filtrare una singola tabella, sarà possibile accedervi per ogni riga (presupponendo un FTS), ma solo per le righe restituite se nell'elenco di selezione. Poiché il piano di esecuzione viene impostato durante l'analisi, ciò implica che le funzioni in select non possono influenzarlo. Un caso di prova per verificare ciò potrebbe essere fatto creando una funzione che imposta un contatore (in un pacchetto o una tabella) e confrontando l'output in base al punto in cui si trova la query.
Chris Saxon,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.