2015-04-09 7 views
6

Supponiamo di avere una funzione PL/SQL che restituisce un valore casuale che verrà utilizzato in un SQL sentence sia come dati restituiti sia nella clausola Order by.Oracle SQL: se utilizzo una funzione sia come campo che in ordine, viene valutata di nuovo?

Ora si potrebbe scrivere la clausola Order by in tre "diversi" modi:

da Index

Select Foo, 
     MyFunction(Foo) orderField 
    From FooTable 
Order By 2 

Chiamando "di nuovo" la funzione

Select Foo, 
     MyFunction(Foo) orderField 
    From FooTable 
Order By MyFunction(Foo) 

Utilizzando l'alias del campo ordine

Select Foo, 
     MyFunction(Foo) orderField 
    From FooTable 
Order By orderField 

Il terzo modo è possibile in quanto la clausola Order By è l'ultima del select da analizzare e quindi Oracle già conosce l'alias.

La mia domanda è, c'è qualche differenza nell'elaborazione o nella prestazione di queste tre domande? In particolare, il secondo implicherebbe che la chiamata MyFunction venga valutata di nuovo?

ho cercato di scoprire cerchiamo la documentazione, e eseguendo alcune query da Rospo, oltre ad avere uno sguardo alla explain plan, ma non abbiamo trovato nessuna differenza significativa fino ad ora.

La mia versione Oracle è 11.2.0.3.0, se questo è importante in qualsiasi modo.

+0

Potrebbe forse dipendere se la funzione è deterministica o no? (Comunque, l'alias della colonna è il mio preferito.) – jarlh

+0

@jarlh, potrebbe essere. Sono curioso di sapere se qualcuno conosce la risposta :-) –

risposta

7

Un buon modo per verificare cosa sta succedendo in questi casi è usare sequenze (ma ho oracle versione 12.1). Ad esempio:

SQL> create sequence func_seq; 

Sequence created. 

SQL> create or replace function foo return number is 
begin 
    return func_seq.nextval; 
end; 
/

Function created. 

Innanzitutto, fare una query che restituiscono due file (senza ORDER BY clausola) e controllare il valore di sequenza:

SQL> select foo from dual connect by level <= 2; 

     FOO 
---------- 
     1 
     2 

SQL> select func_seq.currval from dual; 

    CURRVAL 
---------- 
     2 

Poi una query con ORDER BY:

SQL> select foo from dual connect by level <= 2 order by foo; 

     FOO 
---------- 
     3 
     4 

SQL> select func_seq.currval from dual; 

    CURRVAL 
---------- 
     4 

In entrambi i casi la funzione è stata eseguita 2 volte.
Ma se il vostro funzione prende argomenti, è necessario prestare attenzione ai loro valori: interrogazione

SQL> create or replace function foo(p number) return number is 
begin 
    return func_seq.nextval; 
end; 
/ 

Function created. 

fanno con argomenti diversi:

SQL> select foo(1) from dual connect by level <= 2 order by foo(2); 

    FOO(1) 
---------- 
     6 
     8 

SQL> select func_seq.currval from dual; 

    CURRVAL 
---------- 
     8 

Come possiamo vedere, la funzione è stato eseguito 4 volte.

+0

approccio abbastanza carino per rispondere alla mia domanda, grazie! –

+0

@Dmitry puoi controllare l'ordine per pippo (1) * 2? Non riesco a portare la funzione in esecuzione in sql fiddle –

+0

@PavelGatnar Nel caso di 'order by foo (1) * la funzione 2' viene eseguita 4 volte (come hai scritto nella risposta). – Dmitry

2

La funzione viene valutata solo una volta nel tuo caso, l'espressione nella clausola ORDER BY funge solo da riferimento a una colonna nella clausola SELECT. Quando l'espressione non corrisponde, la funzione verrà valutata due volte, ad es.

Select Foo, 
     MyFunction(Foo) orderField 
From FooTable 
Order By MyFunction(Foo)*2 

mi si aspetterebbe Oracle memorizza i risultati delle funzioni deterministiche (questo deve essere esplicitamente indicato nella definizione della funzione), quindi in questi casi il risultato in cache viene riutilizzato.

Problemi correlati