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
如果在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>
什么情况下函数影响性能
其实自定义函数影响性能,主要在于函数(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 中使用自定义代码片段?