您在这里:首页 > 学员专区 > 技术文章
Oracle视频
Oracle
CUUG课程

利用DETERMINISTIC声明提高性能(一)

 


虽然Oracle提供的DETERMINISTIC声明,本意是确保函数的确定性,但是如何合理利用,是可以用来提高性能的。

这一篇描述ARRAY对性能的影响。

 

 

关于DETERMINISTIC函数,以前已经写过一些文章了,不过对于DETERMINISTIC声明用来提高性能只是简单提了一句,并没有展开来说。

由于函数声明了DETERMINISTIC特性,Oracle对于相同的输入,可以只运行一次,而这对于代码比较复杂,调用时间较长的函数而言,确实可以提高性能。

但是在上面的几篇文章中也提到了,DETERMINISTIC是基于调用的,因此使用DETERMINISTIC不但与输入参数是否重复有关,也与SQL调用次数有关。

一个前面文章提到过的简单的例子就是sqlplus的数组方式FETCH数据,不同的array的值,就会影响DETERMINISTIC函数的运行次数,哪怕

不过这里要澄清以前一个错误的观点,由于设置ARRAY为1后,访问DETERMINISTIC函数发现每两条记录调用一次,当时认为ARRAY方式的最小值是2,但是现在发现,问题和ARRAY无关,导致问题的原因和DETERMINISTIC的实现算法有关。

由于DETERMINISTIC并不像RESULT_CACHE那样,在单独的内存区域中保存每次调用的结果,因此Oracle需要判断DETERMINISTIC函数两次输入是否一样,这对于输入参数相同的情况还简单一些,但是对于包含大量变化的变量,就使得函数的调用次数很难预料。

看一个简单的例子来说明这个问题:

SQL> CREATE OR REPLACE FUNCTION F_DETER (V_IN NUMBER)

2 RETURN NUMBER DETERMINISTIC AS

3 BEGIN

4 DBMS_LOCK.SLEEP(1);

5 DBMS_OUTPUT.PUT_LINE(V_IN);

6 RETURN V_IN;

7 END;

8 /

函数已创建。

SQL> CREATE TABLE T_DETER (ID NUMBER, C NUMBER);

表已创建。

SQL> INSERT INTO T_DETER

2 SELECT ROWNUM, 1

3 FROM TAB;

已创建15行。

SQL> SET SERVEROUT ON

SQL> SET TIMING ON

SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';

会话已更改。

已用时间: 00: 00: 00.09

SQL> SHOW ARRAY

arraysize 15

SQL> SELECT ID, F_DETER(C), SYSDATE FROM T_DETER;

ID F_DETER(C) SYSDATE

---------- ---------- -------------------

1 1 2011-05-26 08:10:54

2 1 2011-05-26 08:10:54

3 1 2011-05-26 08:10:54

4 1 2011-05-26 08:10:54

5 1 2011-05-26 08:10:54

6 1 2011-05-26 08:10:54

7 1 2011-05-26 08:10:54

8 1 2011-05-26 08:10:54

9 1 2011-05-26 08:10:54

10 1 2011-05-26 08:10:54

11 1 2011-05-26 08:10:54

12 1 2011-05-26 08:10:54

13 1 2011-05-26 08:10:54

14 1 2011-05-26 08:10:54

15 1 2011-05-26 08:10:54

已选择15行。

1

1

已用时间: 00: 00: 02.80

SQL> CREATE OR REPLACE FUNCTION F_SYSDATE RETURN DATE AS

2 BEGIN

3 RETURN SYSDATE;

4 END;

5 /

函数已创建。

已用时间: 00: 00: 00.04

SQL> SELECT ID, F_DETER(C), F_SYSDATE FROM T_DETER;

ID F_DETER(C) F_SYSDATE

---------- ---------- -------------------

1 1 2011-05-26 08:11:13

2 1 2011-05-26 08:11:14

3 1 2011-05-26 08:11:14

4 1 2011-05-26 08:11:14

5 1 2011-05-26 08:11:14

6 1 2011-05-26 08:11:14

7 1 2011-05-26 08:11:14

8 1 2011-05-26 08:11:14

9 1 2011-05-26 08:11:14

10 1 2011-05-26 08:11:14

11 1 2011-05-26 08:11:14

12 1 2011-05-26 08:11:14

13 1 2011-05-26 08:11:14

14 1 2011-05-26 08:11:14

15 1 2011-05-26 08:11:14

已选择15行。

1

1

已用时间: 00: 00: 02.18

由于对于SYSDATE函数,Oracle做了优化,因为查询中看到的是同一个时间,将SYSDATE封装到一个函数中,可以看到,即使对于ARRAY设置为15的情况,在同一次的调用中,输入参数完全相同,DETERMINISTIC函数也会调用两次。这个就与DETERMINISTIC的具体实现有关系了。

对于DETERMINISTIC和ARRAY的关系以前也描述过,这里不详细展开了,下面看看当参数发生变化的情况:

SQL> UPDATE T_DETER SET C = MOD(ROWNUM, 2);

已更新15行。

已用时间: 00: 00: 00.10

SQL> SELECT ID, F_DETER(C), F_SYSDATE FROM T_DETER;

ID F_DETER(C) F_SYSDATE

---------- ---------- -------------------

1 1 2011-05-26 08:46:02

2 0 2011-05-26 08:46:03

3 1 2011-05-26 08:46:04

4 0 2011-05-26 08:46:04

5 1 2011-05-26 08:46:04

6 0 2011-05-26 08:46:04

7 1 2011-05-26 08:46:04

8 0 2011-05-26 08:46:04

9 1 2011-05-26 08:46:04

10 0 2011-05-26 08:46:04

11 1 2011-05-26 08:46:04

12 0 2011-05-26 08:46:04

13 1 2011-05-26 08:46:04

14 0 2011-05-26 08:46:04

15 1 2011-05-26 08:46:04

已选择15行。

1

0

1

已用时间: 00: 00: 03.22

SQL> SET ARRAY 5

SQL> SELECT ID, F_DETER(C), F_SYSDATE FROM T_DETER;

ID F_DETER(C) F_SYSDATE

---------- ---------- -------------------

1 1 2011-05-26 08:46:50

2 0 2011-05-26 08:46:51

3 1 2011-05-26 08:46:52

4 0 2011-05-26 08:46:52

5 1 2011-05-26 08:46:52

6 0 2011-05-26 08:46:52

7 1 2011-05-26 08:46:53

8 0 2011-05-26 08:46:54

9 1 2011-05-26 08:46:54

10 0 2011-05-26 08:46:54

11 1 2011-05-26 08:46:54

12 0 2011-05-26 08:46:55

13 1 2011-05-26 08:46:56

14 0 2011-05-26 08:46:56

15 1 2011-05-26 08:46:56

已选择15行。

1

0

1

1

0

0

1

已用时间: 00: 00: 07.50

SQL> SET ARRAY 2

SQL> SELECT ID, F_DETER(C), F_SYSDATE FROM T_DETER;

ID F_DETER(C) F_SYSDATE

---------- ---------- -------------------

1 1 2011-05-26 08:48:25

2 0 2011-05-26 08:48:26

3 1 2011-05-26 08:48:27

4 0 2011-05-26 08:48:28

5 1 2011-05-26 08:48:29

6 0 2011-05-26 08:48:30

7 1 2011-05-26 08:48:31

8 0 2011-05-26 08:48:32

9 1 2011-05-26 08:48:33

10 0 2011-05-26 08:48:34

11 1 2011-05-26 08:48:35

12 0 2011-05-26 08:48:36

13 1 2011-05-26 08:48:37

14 0 2011-05-26 08:48:38

15 1 2011-05-26 08:48:39

已选择15行。

1

0

1

0

1

0

1

0

1

0

1

0

1

0

1

已用时间: 00: 00: 15.38

可以看到,仅仅是两个不同参数的交替出现,在ARRAY为5的情况下,Oracle的DETERMINISTIC的调用方式已经很复杂了,不过有一定是确定的,当ARRARY设置为2时,DETERMINISTIC将完全失效,这种情况下,得不到任何性能上的好处。

而如果不同参数的个数设置为3个,则情况会更加复杂:

SQL> UPDATE T_DETER SET C = MOD(ROWNUM, 3);

已更新15行。

已用时间: 00: 00: 00.03

SQL> SET ARRAY 15

SQL> SELECT ID, F_DETER(C), F_SYSDATE FROM T_DETER;

ID F_DETER(C) F_SYSDATE

---------- ---------- -------------------

1 1 2011-05-26 08:55:59

2 2 2011-05-26 08:56:00

3 0 2011-05-26 08:56:01

4 1 2011-05-26 08:56:02

5 2 2011-05-26 08:56:02

6 0 2011-05-26 08:56:02

7 1 2011-05-26 08:56:02

8 2 2011-05-26 08:56:02

9 0 2011-05-26 08:56:02

10 1 2011-05-26 08:56:02

11 2 2011-05-26 08:56:02

12 0 2011-05-26 08:56:02

13 1 2011-05-26 08:56:02

14 2 2011-05-26 08:56:02

15 0 2011-05-26 08:56:02

已选择15行。

1

2

0

1

已用时间: 00: 00: 04.25

SQL> SET ARRAY 5

SQL> SELECT ID, F_DETER(C), F_SYSDATE FROM T_DETER;

ID F_DETER(C) F_SYSDATE

---------- ---------- -------------------

1 1 2011-05-26 08:56:19

2 2 2011-05-26 08:56:20

3 0 2011-05-26 08:56:21

4 1 2011-05-26 08:56:22

5 2 2011-05-26 08:56:22

6 0 2011-05-26 08:56:22

7 1 2011-05-26 08:56:23

8 2 2011-05-26 08:56:24

9 0 2011-05-26 08:56:25

10 1 2011-05-26 08:56:25

11 2 2011-05-26 08:56:25

12 0 2011-05-26 08:56:26

13 1 2011-05-26 08:56:27

14 2 2011-05-26 08:56:28

15 0 2011-05-26 08:56:28

已选择15行。

1

2

0

1

1

2

0

0

1

2

已用时间: 00: 00: 10.19

虽然DETERMINISTIC的调用实现很复杂,但是这里至少可以得出一个结论,如果希望通过DETERMINISTIC来获取性能收益,那么采用批量方式是必须的,而且数组的值相对而言越大对于性能的帮助会越大,因此每次数组获取数据,被认为是一次调用,而DETERMINISTIC函数主要是在一次调用中生效。当然根据上面测试的结果,跨调用的生效也是可能存在的,但是多次调用必然会导致函数更多次数的调用,如果仅从DETERMINISTIC函数的调用效果考虑,ARRAY值越大,对于性能的提高就越大。

 


(以上内容摘于网络,如有侵权,请告之,将第一时间删除)

相关文章 [上一篇] 胡毅讲师
010-88589926(88587026)
CUUG热门培训课程
Oracle DBA就业培训
CUUG名师
网络课程
技术沙龙
最新动态

总机:(010)-88589926,88589826,88587026 QQ讨论群:243729577 182441349 邮箱:cuug_bj@cuug.com
通信地址:北京市海淀区紫竹院路98号北京化工大学科技园609室(CUUG)邮政编码:100089 
中国UNIX用户协会 Copyright 2010  ALL Rights Reserved 北京神脑资讯技术有限公司
京ICP备11008061号  京公网安备110108006275号