sql >> Database teknologi >  >> RDS >> Oracle

Hvordan behandler Oracle lagrede funktionskald i SQL?

Det er et rigtig godt spørgsmål.

Jeg prøvede først at oprette tabel og indsætte eksempeldata (kun fem rækker):

create table my_table(value number);
insert into my_table(value) values(1);
insert into my_table(value) values(2);
insert into my_table(value) values(3);
insert into my_table(value) values(4);
insert into my_table(value) values(5);
 

Jeg lavede en simpel testpakke til at teste dette.

create or replace package my_package is
  g_counter_SELECT PLS_INTEGER := 0; -- counter for SELECT statement
  g_counter_WHERE  PLS_INTEGER := 0; -- counter for WHERE clause
  function my_function(number_in in number, type_in in varchar2) return number;
  procedure reset_counter;
end;
/
 

Og krop...

create or replace package body my_package is
  function my_function(number_in in number, type_in in varchar2) return number is
  begin
    IF(type_in = 'SELECT') THEN
        g_counter_SELECT := g_counter_SELECT + 1;
    ELSIF(type_in = 'WHERE') THEN
        g_counter_WHERE := g_counter_WHERE + 1;
    END IF;
    return mod(number_in, 2);
  end;
  procedure reset_counter is
  begin
    g_counter_SELECT := 0;
    g_counter_WHERE := 0;
  end;
end;
/
 

Nu kan vi køre test på Oracle 9i (på 11g er de samme resultater):

-- reset counter
exec my_package.reset_counter();

-- run query
select t.value, my_package.my_function(t.value, 'SELECT')
  from my_table t
 where my_package.my_function(t.value, 'WHERE') = 1;

-- print result
exec dbms_output.put_line('Count (SELECT) = ' || my_package.g_counter_SELECT);
exec dbms_output.put_line('Count (WHERE) = ' || my_package.g_counter_WHERE);
 

Resultatet er:

DBMS Output (Session: [1] [email protected] at: 08.09.2010 01:50:04): 
-----------------------------------------------------------------------
Count (SELECT) = 3
Count (WHERE) = 5
 

Her er plantabellen:

-------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost | -------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | |* 1 | TABLE ACCESS FULL | MY_TABLE | | | | --------------------------------------------------------------------

Hvilket betyder, at funktionen (i WHERE calues) kaldes for hver række i tabellen (i tilfælde af FULD TABLE SCAN). I SELECT-sætningen lanceres lige så mange gange overholde betingelse WHERE my_function =1

Nu... test din anden forespørgsel (samme resultater på Oracle9i og 11g)

Resultatet er:

DBMS Output (Session: [1] [email protected] at: 08.09.2010 02:08:04): 
-----------------------------------------------------------------------
Count (SELECT) = 8
Count (WHERE) = 0
 

Forklar almindeligt udseende som dette (for VÆLG optimeringstilstand):

-------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost | -------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | |* 1 | TABLE ACCESS FULL | MY_TABLE | | | | --------------------------------------------------------------------

SPØRGSMÅL ER:Hvorfor tælle (SELECT) =8?

Fordi Oracle først kørte underforespørgsel (i mit tilfælde med FULD TABLE SCAN, er det 5 rækker =5 kalder my_function i SELECT-sætning):

select t.value, my_package.my_function(t.value, 'SELECT') func_value from my_table t
 

Og end for denne visning (underforespørgsel er som visning) køres 3 gange (på grund af tilstanden, hvor subquery.func_value =1) kalder igen funktionen min_funktion.

Personligt anbefaler jeg ikke at bruge funktionen i WHERE-sætningen, men jeg indrømmer, at nogle gange er dette uundgåeligt.

Som det værst tænkelige eksempel på dette illustreres af følgende:

select t.value, my_package.my_function(t.value, 'SELECT')
  from my_table t
 where my_package.my_function(t.value, 'WHERE') = my_package.my_function(t.value, 'WHERE')
   and my_package.my_function(t.value, 'WHERE') = my_package.my_function(t.value, 'WHERE')
   and my_package.my_function(t.value, 'WHERE') = my_package.my_function(t.value, 'WHERE')
   and my_package.my_function(t.value, 'WHERE') = my_package.my_function(t.value, 'WHERE')
   and my_package.my_function(t.value, 'WHERE') = my_package.my_function(t.value, 'WHERE');
 

Hvor resultatet på Oracle 9i er :

Count (SELECT) = 5
Count (WHERE) = 50
 

Og på Oracle 11g er :

Count (SELECT) = 5
Count (WHERE) = 5
 

Hvilket i dette tilfælde viser, at nogle gange kan brugen af ​​funktioner være kritisk for ydeevnen. I andre tilfælde (11g) løser det selve databasen.



  1. Fremstil en outputfil i fladt format med fast bredde fra en SQL-forespørgsel

  2. Sådan sletter du elementer fra SQLite-databasen med SQLiteOpenHelper-klassen

  3. Ecto-forespørgsel - Datoer + Postgres-intervaller + Forespørgselsinterpolation

  4. Laravel Eloquent sammenligne dato fra datetime felt