sql >> Database >  >> RDS >> Oracle

Hoe verwerkt Oracle opgeslagen functieaanroepen in SQL?

Het is echt een goede vraag.

Ik heb eerst geprobeerd een tabel te maken en voorbeeldgegevens in te voegen (slechts vijf rijen):

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);

Ik heb een eenvoudig testpakket gemaakt om dit te testen.

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;
/

En lichaam...

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 kunnen we testen uitvoeren op Oracle 9i (op 11g zijn dezelfde resultaten):

-- 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);

Resultaat is:

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

Hier is de plantabel:

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

Dat betekent dat de functie (in WHERE-calues) wordt aangeroepen voor elke rij van de tabel (in het geval van FULL TABLE SCAN). In de SELECT-instructie wordt net zo vaak gestart als voldoen aan voorwaarde WHERE my_function =1

Nu... test uw tweede zoekopdracht (dezelfde resultaten op Oracle9i en 11g)

Resultaat is:

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

Leg uit dat het er zo uitziet (voor CHOOSE optimizer-modus):

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

VRAAG IS:Waarom tellen (SELECT) =8?

Omdat Oracle eerst een subquery uitvoert (in mijn geval met FULL TABLE SCAN zijn het 5 rijen =5 roept my_function aan in de SELECT-instructie):

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

En dan voor deze weergave (subquery is als weergave) 3 keer uitvoeren (vanwege de voorwaarde waarbij subquery.func_value =1) opnieuw de functie my_function aanroept.

Persoonlijk raad ik het niet aan om de functie in de WHERE-clausule te gebruiken, maar ik geef toe dat dit soms onvermijdelijk is.

Het slechtst mogelijke voorbeeld hiervan wordt geïllustreerd door het volgende:

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');

Waar het resultaat op Oracle 9i is :

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

En op Oracle 11g is :

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

Wat in dit geval laat zien dat het gebruik van functies soms van cruciaal belang kan zijn voor de prestaties. In andere gevallen (11g) lost het de database zelf op.



  1. Hoe verwijder ik specifieke rijen in SQLite Database?

  2. Maak een ROLLING-som over een bepaalde periode in mysql

  3. Herstelprobleem Heroku-database

  4. SELECT LAST_INSERT_ID() retourneert 0 na gebruik van de voorbereide instructie