Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Oracle xử lý các lệnh gọi hàm được lưu trữ trong SQL như thế nào?

Đó là một câu hỏi thực sự hay.

Lần đầu tiên tôi đã thử tạo bảng và chèn dữ liệu mẫu (chỉ năm hàng):

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

Tôi đã tạo một gói thử nghiệm đơn giản để kiểm tra điều này.

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

Và cơ thể ...

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

Bây giờ, chúng ta có thể chạy thử nghiệm trên Oracle 9i (vào 11g đều có kết quả tương tự):

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

Kết quả là:

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

Đây là bảng kế hoạch:

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

Điều đó có nghĩa là hàm (trong giá trị WHERE) được gọi cho mọi hàng của bảng (trong trường hợp QUÉT BẢNG ĐẦY ĐỦ). Trong câu lệnh SELECT được khởi chạy giống như nhiều lần tuân thủ điều kiện WHERE my_ Chức năng =1

Bây giờ ... hãy kiểm tra truy vấn thứ hai của bạn (kết quả tương tự trên Oracle9i và 11g)

Kết quả là:

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

Giải thích giao diện đơn giản như thế này (đối với CHỌN chế độ trình tối ưu hóa):

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

CÂU HỎI LÀ: Tại sao Đếm (CHỌN) =8?

Vì Oracle chạy truy vấn con đầu tiên (trong trường hợp của tôi với FULL TABLE SCAN, nó có 5 hàng =5 gọi my_ functions trong câu lệnh SELECT):

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

Và hơn đối với dạng xem này (truy vấn con giống như dạng xem) chạy 3 lần (do điều kiện trong đó subquery.func_value =1) lại gọi hàm my_ functions.

Cá nhân tôi không khuyến khích sử dụng hàm trong mệnh đề WHERE, nhưng tôi thừa nhận rằng đôi khi điều này là không thể tránh khỏi.

Ví dụ tồi tệ nhất có thể được minh họa bằng cách sau:

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

Kết quả trên Oracle 9i ở đâu :

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

Và trên Oracle 11g là :

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

Trong trường hợp này cho thấy rằng đôi khi việc sử dụng các chức năng có thể rất quan trọng đối với hiệu suất. Trong các trường hợp khác (11g), nó tự giải quyết cơ sở dữ liệu.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Truy vấn LISTAGG ORA-00937:không phải là một hàm nhóm đơn

  2. Oracle ngủ đông ORA-01461 CLOB

  3. ora-01406 Lỗi khi tìm nạp các giá trị bằng OCI

  4. Oracle - lấy ngày hiện tại được định dạng

  5. truy vấn xóa oracle mất quá nhiều thời gian