ORACLE当中自定义函数性优化浅析

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ORACLE当中自定义函数性优化浅析相关的知识,希望对你有一定的参考价值。

 

为什么函数影响性能

 

在SQL语句中,如果不合理的使用函数(Function)就会严重影响性能,其实这里想说的是PL/SQL中的自定义函数,反而对于一些内置函数而言,影响性能的可能性较小。那么为什么SQL语句当中,不合理的使用函数会影响性能呢?

 

    在SELECT语句中调用函数时,那么查询返回的结果集中的每一行都会调用该函数。如果该函数需要执行1秒,返回的结果集是10行,那么此时SQL语句就需要10秒,如果该函数执行时间需要3秒,返回的结果集是10000条记录,那么这个时间就是30000秒~= 500分钟。是否很恐怖!因为生产环境中自定义函数有时候会出现复杂的业务逻辑,导致自定义函数性能开销较高,如果出现不合理调用,那么很容易就会出现性能问题。 下面我们简单来演示一个例子。

 

 

CREATE TABLE TEST
(
   ID  NUMBER
);
 
 
DECLARE RowIndex NUMBER;
BEGIN
RowIndex :=1;
WHILE RowIndex <= 8 LOOP
    INSERT INTO TEST
    SELECT RowIndex  FROM DUAL;
    
     RowIndex := RowIndex +1;
END LOOP;
COMMIT;
END;
/

 

--创建函数SLOW_FUNCTION,使用DBMS_LOCK.SLEEP休眠2秒,模拟这个函数较慢。

CREATE OR REPLACE FUNCTION SLOW_FUNCTION(p_value  IN NUMBER)
RETURN NUMBER
AS
BEGIN
    DBMS_LOCK.SLEEP(2);
    RETURN p_value+10;
END;
/

 

 

SQL> SET TIMING ON; 
SQL> SELECT * FROM TEST;
 
        ID
----------
         1
         2
         3
         4
         5
         6
         7
         8
 
8 rows selected.
 
Elapsed: 00:00:00.00
SQL> SELECT SLOW_FUNCTION(ID) FROM TEST;
 
SLOW_FUNCTION(ID)
-----------------
               11
               12
               13
               14
               15
               16
               17
               18
 
8 rows selected.
 
Elapsed: 00:00:16.01

 

clip_image001

 

 

如果在WHERE当中使用函数,由于有8条记录,而每次调用函数需要Sleep 2秒, 总共耗费2*8=16秒。所以在WHERE条件中,也要谨慎使用自定义函数。

 

SQL> SET AUTOTRACE OFF;
SQL> 
SQL> SELECT * FROM TEST
  2  WHERE SLOW_FUNCTION(ID)>15;
 
        ID
----------
         6
         7
         8
 
Elapsed: 00:00:16.01
SQL> 

 

clip_image002

 

 

 

 

 

什么情况下函数影响性能

 

 

其实自定义函数影响性能,主要在于函数(Function)调用的次数或函数(Function)本身的业务逻辑是否复杂,如果SELECT查询中调用次数很少,影响还是非常小的。如下所示,如果只调用一次的话,这个影响还是非常小的。

 

 

 
SQL> SELECT SLOW_FUNCTION(ID) FROM TEST WHERE ID=2;
 
SLOW_FUNCTION(ID)
-----------------
               12
 
Elapsed: 00:00:02.01

 

 

其次,如果函数实现的业务逻辑简单,即使调用次数多,对性能影响也很小。我们改写一下下面函数,通过实验来验证测试一下,如下所示: 

 

CREATE OR REPLACE FUNCTION SLOW_FUNCTION(p_value  IN NUMBER)
RETURN NUMBER
AS
BEGIN
    RETURN p_value+10;
END;
/

 

然后创建一个存储过程,来测试一下循环次数对性能的影响。

 

CREATE OR REPLACE PROCEDURE TEST_SLOW_FUNCTION(ITER IN NUMBER)
AS RESULT VARCHAR2(60);
BEGIN
    FOR I IN 1 .. ITER LOOP
    SELECT SLOW_FUNCTION(I) INTO RESULT FROM DUAL;
    END LOOP;
END TEST_SLOW_FUNCTION;
/

 

如下所示,当函数业务逻辑简单,性能开销很低时,循环次数对性能的影响反而很小。10次循环调用跟1000000次循环调用差别是3秒多。可见如果自定义函数的业务逻辑简单,循环次数对性能影响较小。 

 

SQL> EXEC TEST_SLOW_FUNCTION(10);
 
PL/SQL procedure successfully completed.
 
Elapsed: 00:00:00.01
SQL> EXEC TEST_SLOW_FUNCTION(10000);
 
PL/SQL procedure successfully completed.
 
Elapsed: 00:00:00.40
SQL> EXEC TEST_SLOW_FUNCTION(100000);
 
PL/SQL procedure successfully completed.
 
Elapsed: 00:00:03.64

如何在 Toad for Oracle 中使用自定义代码片段?

python第十四课--排序及自定义函数

VSCode自定义代码片段——声明函数

VSCode自定义代码片段8——声明函数

片段中的按钮自定义视图

如何优化Oracle在where条件中用了自定义函数的SQL语句