您的位置:首页 > 数据库 > Oracle

Oracle技术之利用DETERMINISTIC声明提高性能(二)  

2013-07-09 10:07 302 查看
虽然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来提高函数的性能,最关键的一点是确保调用函数时,输入参数是排序的。

oracle视频教程请关注:http://u.youku.com/user_video/id_UMzAzMjkxMjE2.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息