虽然Oracle提供的DETERMINISTIC声明,本意是确保函数的确定性,但是如何合理利用,是可以用来提高性能的。
这一篇描述参数顺序对性能的影响。
上一篇文章提到了,如果希望通过DETERMINISTIC来获取性能收益,那么采用批量方式是必须的,而且数组的值相对而言越大对于性能的帮助会越大。
但是这里存在一个问题,如果需要处理的数据量本身很大,虽然重复的输入参数不少,但是总的参数不同的值更多,那么即使将ARRAY的值设置到1000,能带来的性能收益也很有限,因为即使1000次调用,也不能保证参数完全一样出现多次,而如果无限制的增大ARRAY,虽然从DETERMINISTIC函数的角度讲可以提高性能,但是对于内存的占用等其他方面,会带来性能的下降,显然一味的扩大批量并不是问题的解决之道。
其实解决这个问题很简单,就是在调用DETERMINISTIC函数之前,对函数的参数进行排序,确保相同的参数顺序调用,这样DETERMINISTIC函数执行的次数最少。
继续使用上一篇文章的例子,看看排序后DETERMINISTIC函数的调用次数:
SQL> UPDATE T_DETER SET C = 1;
已更新15行。
已用时间: 00: 00: 00.17
SQL> SELECT ID, F_DETER(C), F_SYSDATE FROM T_DETER;
ID F_DETER(C) F_SYSDATE
---------- ---------- -------------------
1 1 2011-05-26 14:26:12
2 1 2011-05-26 14:26:13
3 1 2011-05-26 14:26:13
4 1 2011-05-26 14:26:13
5 1 2011-05-26 14:26:13
6 1 2011-05-26 14:26:13
7 1 2011-05-26 14:26:13
8 1 2011-05-26 14:26:13
9 1 2011-05-26 14:26:13
10 1 2011-05-26 14:26:13
11 1 2011-05-26 14:26:13
12 1 2011-05-26 14:26:13
13 1 2011-05-26 14:26:13
14 1 2011-05-26 14:26:13
15 1 2011-05-26 14:26:13
已选择15行。
1
1
已用时间: 00: 00: 02.29
SQL> SELECT ID, F_DETER(C), F_SYSDATE FROM (SELECT * FROM T_DETER ORDER BY C);
ID F_DETER(C) F_SYSDATE
---------- ---------- -------------------
1 1 2011-05-26 14:26:35
15 1 2011-05-26 14:26:35
3 1 2011-05-26 14:26:35
4 1 2011-05-26 14:26:35
5 1 2011-05-26 14:26:35
6 1 2011-05-26 14:26:35
7 1 2011-05-26 14:26:35
8 1 2011-05-26 14:26:35
9 1 2011-05-26 14:26:35
10 1 2011-05-26 14:26:35
11 1 2011-05-26 14:26:35
12 1 2011-05-26 14:26:35
13 1 2011-05-26 14:26:35
14 1 2011-05-26 14:26:35
2 1 2011-05-26 14:26:35
已选择15行。
1
已用时间: 00: 00: 01.10
可以看到,由于执行了排序,DETERMINISTIC函数不用再次检查输入参数是否相等,因此在SQL运行期间只调用了一次:
SQL> SHOW ARRAY
arraysize 15
SQL> SET ARRAY 1
SQL> SELECT ID, F_DETER(C), F_SYSDATE FROM (SELECT * FROM T_DETER ORDER BY C);
ID F_DETER(C) F_SYSDATE
---------- ---------- -------------------
1 1 2011-05-26 14:28:31
15 1 2011-05-26 14:28:31
3 1 2011-05-26 14:28:31
4 1 2011-05-26 14:28:31
5 1 2011-05-26 14:28:31
6 1 2011-05-26 14:28:31
7 1 2011-05-26 14:28:31
8 1 2011-05-26 14:28:31
9 1 2011-05-26 14:28:31
10 1 2011-05-26 14:28:31
11 1 2011-05-26 14:28:31
12 1 2011-05-26 14:28:31
13 1 2011-05-26 14:28:31
14 1 2011-05-26 14:28:31
2 1 2011-05-26 14:28:31
已选择15行。
1
已用时间: 00: 00: 01.17
即使将ARRAY设置为1,也对DETERMINISTIC的调用次数没有影响了。
下面看看多个参数值的情况:
SQL> UPDATE T_DETER SET C = MOD(ROWNUM, 2);
已更新15行。
已用时间: 00: 00: 00.03
SQL> SELECT ID, F_DETER(C), F_SYSDATE FROM (SELECT * FROM T_DETER ORDER BY C);
ID F_DETER(C) F_SYSDATE
---------- ---------- -------------------
2 0 2011-05-26 14:29:59
14 0 2011-05-26 14:29:59
12 0 2011-05-26 14:29:59
10 0 2011-05-26 14:29:59
8 0 2011-05-26 14:29:59
6 0 2011-05-26 14:29:59
4 0 2011-05-26 14:29:59
11 1 2011-05-26 14:29:59
7 1 2011-05-26 14:29:59
13 1 2011-05-26 14:29:59
5 1 2011-05-26 14:29:59
9 1 2011-05-26 14:29:59
3 1 2011-05-26 14:29:59
15 1 2011-05-26 14:29:59
1 1 2011-05-26 14:29:58
已选择15行。
1
0
已用时间: 00: 00: 02.08
即使ARRAY仍然为1,对于DETERMINISTIC函数也没有影响了,排序后DETERMINISTIC函数对于不同的参数值仅调用一次。
同时,这里也有一个有趣的现象,就是Oracle先执行的C=1的函数调用,然后才是C=0的调用。从SELECT查询返回的时间还有SERVEROUT的输出都证实了这一点,但是这与我们的理解不符,因为查询要求SQL先排序,然后运行函数,Oracle在这里并没有完全按照SQL的语法来运行,而是先调用了DETERMINISTIC函数,输出的时候再对结果排序。但由于指定了排序,事实上即使DETERMINISTIC函数即使在排序前调用,仍然使用了排序的特性,因此只运行了一次。
如果要使用DETERMINISTIC来提高函数的性能,最关键的一点是确保调用函数时,输入参数是排序的。
(以上内容摘于网络,如有侵权,请告之,将第一时间删除)
总机:(010)-88589926,88589826,88587026 QQ讨论群:243729577 182441349 邮箱:cuug_bj@cuug.com
通信地址:北京市海淀区紫竹院路98号北京化工大学科技园609室(CUUG)邮政编码:100089
中国UNIX用户协会 Copyright 2010 ALL Rights Reserved 北京神脑资讯技术有限公司
京ICP备11008061号 京公网安备110108006275号