Oracle
 sql >> Baza danych >  >> RDS >> Oracle

W jaki sposób Oracle przetwarza wywołania funkcji składowanych w SQL?

To naprawdę dobre pytanie.

Najpierw spróbowałem utworzyć tabelę i wstawić przykładowe dane (tylko pięć wierszy):

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

Zrobiłem prosty pakiet testowy do testowania tego.

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

I ciało...

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

Teraz możemy uruchomić test na Oracle 9i (na 11g są takie same wyniki):

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

Wynik to:

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

Oto tabela planów:

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

Co oznacza, że ​​funkcja (w obliczeniach WHERE) jest wywoływana dla każdego wiersza tabeli (w przypadku FULL TABLE SCAN). W instrukcji SELECT jest uruchamiana tyle samo razy spełnia warunek WHERE moja_funkcja =1

Teraz... przetestuj drugie zapytanie (te same wyniki na Oracle9i i 11g)

Wynik to:

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

Wyjaśnij zwykły wygląd tak (dla trybu WYBIERZ optymalizatora):

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

PYTANIE TO:Dlaczego liczba (SELECT) =8?

Ponieważ Oracle najpierw uruchomi podzapytanie (w moim przypadku z FULL TABLE SCAN, to 5 wierszy =5 wywołań my_function w instrukcji SELECT):

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

I wtedy dla tego widoku (podzapytanie jest jak widok) uruchom 3 razy (ze względu na warunek, w którym subquery.func_value =1) ponownie wywołaj funkcję moja_funkcja.

Osobiście nie polecam używania funkcji w klauzuli WHERE, ale przyznaję, że czasami jest to nieuniknione.

Najgorszym możliwym przykładem tego jest:

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

Gdzie jest wynik w Oracle 9i :

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

A na Oracle 11g jest :

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

Co w tym przypadku pokazuje, że czasami użycie funkcji może mieć krytyczne znaczenie dla wydajności. W innych przypadkach (11g) sam rozwiązuje bazę danych.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Formularze Oracle w R12/R12.2

  2. Masz tabelę Oracle o nazwie słowo zastrzeżone, jakie problemy mogą się pojawić?

  3. 4 sposoby wstawiania wielu wierszy w Oracle

  4. Model formatu liczb TO_Char w Oracle

  5. Oracle Naturalne łączenia i liczenie(1)