sql >> Databasteknik >  >> RDS >> Oracle

Hur bearbetar Oracle lagrade funktionsanrop i SQL?

Det är en riktigt bra fråga.

Jag försökte först skapa tabell och infoga exempeldata (endast fem rader):

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

Jag gjorde ett enkelt testpaket för att testa detta.

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

Och kropp...

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öra test på Oracle 9i (på 11g är samma resultat):

-- 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 är:

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

Här är plantabellen:

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

Vilket innebär att funktionen (i WHERE calues) anropas för varje rad i tabellen (vid FULL TABELL SCAN). I SELECT-satsen startas lika många gånger följa villkoret WHERE my_function =1

Nu... testa din andra fråga (samma resultat på Oracle9i och 11g)

Resultatet är:

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

Förklara vanligt utseende så här (för VÄLJ optimeringsläge):

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

FRÅGA ÄR:Varför räkna (SELECT) =8?

Eftersom Oracle först körde subquery (i mitt fall med FULL TABLE SCAN, är det 5 rader =5 anrop my_function i SELECT-satsen):

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

Och än för denna vy (underfråga är som vy) kör 3 gånger (på grund av tillståndet där subquery.func_value =1) anropa funktionen my_function igen.

Personligen rekommenderar jag inte att använda funktionen i WHERE-satsen, men jag medger att detta ibland är oundvikligt.

Som det sämsta tänkbara exemplet på detta illustreras av följande:

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

Var resultatet på Oracle 9i är :

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

Och på Oracle 11g är :

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

Vilket i det här fallet visar att användningen av funktioner ibland kan vara avgörande för prestandan. I andra fall (11g) löser den själva databasen.



  1. Vad är det korrekta indexet för att fråga strukturer i arrayer i Postgres jsonb?

  2. python MySQLDB-fråga timeout

  3. MySQL:hur kan jag se ALLA begränsningar på en tabell?

  4. Hur ändrar man standardsorteringen för en tabell?