转- oracle10g-如何提高pl/sql程序的性能

oracle10g-如何提高pl/sql程序的性能()

oracle10g-如何提高pl/sql程序的性能(1)

转自:http://blog.chinaunix.net/u/25176/showart_1089339.html

PLSQL_OPTIMIZE_LEVEL

Property

Description

Parameter type

Integer

Default value

DE>2DE>

Modifiable

DE>ALTER SESSIONDE>, DE>ALTER SYSTEMDE>

Range of values

DE>0DE> to DE>2DE>

 

DE>PLSQL_OPTIMIZE_LEVELDE> specifies the optimization level that will be used to compile PL/SQL library units. The higher the setting of this parameter, the more effort the compiler makes to optimize PL/SQL library units.

Values:

·  DE>0DE>

Maintains the evaluation order and hence the pattern of side effects, exceptions, and package initializations of Oracle9i and earlier releases. Also removes the new semantic identity of DE>BINARY_INTEGERDE> and DE>PLS_INTEGERDE> and restores the earlier rules for the evaluation of integer expressions. Although code will run somewhat faster than it did in Oracle9i, use of level 0 will forfeit most of the performance gains of PL/SQL in Oracle Database 10g.

·  DE>1DE>

Applies a wide range of optimizations to PL/SQL programs including the elimination of unnecessary computations and exceptions, but generally does not move source code out of its original source order.

·  DE>2DE>

Applies a wide range of modern optimization techniques beyond those of level 1 including changes which may move source code relatively far from its original location.

Generally, setting this parameter to DE>2DE> pays off in better execution performance. If, however, the compiler runs slowly on a particular source module or if optimization does not make sense for some reason (for example, during rapid turnaround development), then setting this parameter to DE>1DE> will result in almost as good a compilation with less use of compile-time resources.

        必须说明的是,以下内容是属于学习笔记的部分,虽然PDFE文也看得懂,但是还是觉得翻译为自己的国文看起来更加舒畅一些。
       
此处原文见<<Oracle Database PL/SQL User’s Guide and Reference>>的第十一章节的内容"Tuning PL/SQL Applications for Performance"--调整Pl/sql应用程序的性能。
       
一,和PL/SQL编译相关的初始化参数
       
自然这里的初始化参数指的就是init文件中的参数。
               PLSQL_CCFLAGS        
主要用于条件编译中
               PLSQL_CODE_TYPE   
可以选择的值是NATIVE还是INTERPRETED
               PLSQL_DEBUG              true/false
true的时候,代码别编译为Interpreted类型以便调试。。
               PLSQL_NATIVE_LIBRARY_DIR       
全编译时候存放库的路径
               PLSQL_NATIVE_LIBRARY_SUBDIR_COUNT   
这和上一个是配对使用的,也是用于全编译。
               PLSQL_OPTIMIZE_LEVEL  
特别介绍以下,不过oracle建议我们一般不要修改。
              
---------------------
                   
原文不晦涩,也就不翻译了。
                    PLSQL_OPTIMIZE_LEVEL specifies the optimization level that will be used to

compile PL/SQL library units. The higher the setting of this parameter, the more effort
the compiler makes to optimize PL/SQL library units.
Values:
■ 0
(主要为了向下兼容)
Maintains the evaluation order and hence the pattern of side effects, exceptions,
and package initializations of Oracle9i and earlier releases. Also removes the new
semantic identity of BINARY_INTEGER and PLS_INTEGER and restores the earlier
rules for the evaluation of integer expressions. Although code will run somewhat
faster than it did in Oracle9i, use of level 0 will forfeit most of the performance
gains of PL/SQL in Oracle Database 10g.
■ 1
(一般化,不过一般不做特殊优化)
Applies a wide range of optimizations to PL/SQL programs including the
elimination of unnecessary computations and exceptions, but generally does not
move source code out of its original source order.
■ 2
(和1类似,但是可能会修改你的源码,在生成的库中,代码的顺序会变化)
Applies a wide range of modern optimization techniques beyond those of level 1
including changes which may move source code relatively far from its original
location.
Generally, setting this parameter to 2 pays off in better execution performance. If,
however, the compiler runs slowly on a particular source module or if optimization
does not make sense for some reason (for example, during rapid turnaround
development), then setting this parameter to 1 will result in almost as good a
compilation with less use of compile-time resources.
The value of this parameter is stored persistently with the library unit.
最后一句话:在生成的库中总是会存储这个参数的值。

               ---------------------
               PLSQL_WARNINGS       
属于编译的参数,控制可以输出的参数,可以基于sessionsystem的级别修改
               NLS_LENGTH_SEMANTICS. 
这个参数比较玄妙,这是用于控制类型为charvarchar2的列使用字节还是
                                                     
字来存储相关的数据,默认是用单字节(byte),也可以是character,不影响已经存
                                                     
在的数据,不影响SYSTEMsys用户的对象。
       
关于这些参数的定义可以见<<oracle database reference>>,非常的全,至于如何修改它们,则可以参考<<oracle database sql reference>>,这两部书都是特大部头。
       
二,如何优化(或者是优化的原理是什么)
       
有一点很关键的是,10g之后oracle会重新排列代码(相应的plsql_optimize_level2)(应该来说,通常重新排列之后的算法是更好的,当然也许会存在更不好的,这个以后再说)。
       
需要注意的是,你可以自己按照需要调整优化级别参数。
       
对于已经编译好的对象,可以通过视图ALL_PLSQL_OBJECT_SETTINGS来知道优化的级别以及相关编译信息。
      
其次,就是选择优化的时机。如果在进行优化前,先考虑一些基本的也许会更好一些。

      
三、关于避免PLSQL性能问题的指导方针
       3.1 避免CPU过载
             A.
使SQL语句尽可能的高效

o  是否有合适的索引,是否正确的使用了索引

o  是否有最新的统计数据,常常使用DBMS_STATS包来重新统计。

o  使用EXPLAIN PLAN语句或者TKPROF工具分析语句的性能

o  如果需要,就重写sql语句。例如可以使用强制提示

o 考虑用FORALL替代普通的循环来执行INSERT等语句;如果需要轮询查询结果,考虑用BULK  COLLECT语句 

             B. 使函数更有效率
                
如果在SQL查询中使用函数,那么考虑建立一个基于函数的索引;尽可能的把需要使用函数的行的数量
                
降低。(由于很多的内容稍后会有比较详细的描述,所以这里不再赘述了)
             C.
优化循环
             D 
尽可能地使用内建的字符串函数来处理字符串,例如搜索等等。
             E 
对于条件表达式,应该把消耗最小的排在前面,这样有的时候后面复杂的测试可能可以避免。
             F 
尽量减少数据类型的转换
             G 
PLS_INTEGER进行整数运算
             H 
BINARY_FLOAT BINARY_DOUBLE进行浮点运算
       3.2
避免内存过载
             A 
定义VARCHAR2变量类型的时候,不妨大方一些,这反而可以编译溢出。
             B  
把相关的过程放在一个包裹中(PACKAGE),可以减少不必要的I/O .
             C  
把常常用到的包裹钉在共享内存池中,Pin packages in the shared memory pool..。可以用
                   dbms_shared_pool
包裹来处理,具体参考<<ORACLE DATABASE PL/SQL PACKAGES AND Types
                   reference>>
             D 
避免编译中出现的警告。有警告提示,则应该按照提示去改正。
            
      
四,记录并跟踪PL/SQL程序
         4.1 
使用记录API:包裹dbms_profiler.这个包括能够提供收集并保存运行时统计数据的功能。最终的数据被保存在数据库的表格中。
         4.2 
使用跟踪API:包裹DBMS_TRACE.当让要讲究跟踪的策略。对于这点,我觉得使用PL/SQL DEVELOPER很方便。

      
五,减少DML语句循环的消耗、在查询中使用BULK SQL语句
        PL/SQL
引擎把FORALL中的DML语句成批的发送给SQL引擎。SQL引擎通过BULK collect会批量的返回数据。这两种方式都会大大的减少两个引擎之间的通讯成本和管理成本。
        SQL
语句中PL/SQL变量的绑定有三个途径:
        1
:内部绑定:通过INSERT 或者UPDATE语句来完成。
        2
:外部绑定:通过INSERT,UPDATE,DELETE 中的RETURNING语句来完成。
        3
:定义       :通过SELECT或者FETCH语句来完成。
       
此外的一种就是大量绑定(BULK BINDING)
         5.1 
使用FORALL 语句
               5.1.1  FORALL
是如何作用到ROLLBACKS(回滚)
                        
在异常之前的语句都可以提交,异常和异常之后的无法提交。
               5.1.2 
使用%bulk_rowcount属性来计算FORALL影响到的行                                
               5.1.3 
使用%BULK_EXCEPTIONS属性来处理FORALL异常
              
我们需要一个例子,可以从例子中得到许多有益的总结:(其中的employees的格式和数据来源于hr                                                 

DECLARE
    TYPE empid_tab IS TABLE OF employees.employee_id%TYPE;
    emp_sr empid_tab;
    -- create an exception handler for ORA-24381
    errors NUMBER;
    dml_errors EXCEPTION;
    PRAGMA EXCEPTION_INIT(dml_errors, -24381);
BEGIN
    SELECT employee_id BULK COLLECT INTO emp_sr FROM emp_temp
    WHERE hire_date < to_date('1994-12-30','yyyy-mm-dd');
    -- add '_SR' to the job_id of the most senior employees
    FORALL i IN emp_sr.FIRST..emp_sr.LAST SAVE EXCEPTIONS
    UPDATE emp_temp SET job_id = job_id || '_SR'
    WHERE emp_sr(i) = emp_temp.employee_id;
    -- If any errors occurred during the FORALL SAVE EXCEPTIONS,
    -- a single exception is raised when the statement completes.
EXCEPTION
    WHEN dml_errors THEN -- Now we figure out what failed and why.
    FOR I IN emp_sr.FIRST..emp_sr.LAST loop
    if sql%bulk_rowcount(i)<>0 then
         dbms_output.put_line('The  row '||i||' has '||sql%bulk_rowcount(i)||' Updated !');
    else
      dbms_output.put_line('The  row '||i||' has  no rows Updated !');
    end if;
    end loop;
    errors := SQL%BULK_EXCEPTIONS.COUNT;
    DBMS_OUTPUT.PUT_LINE('Number of statements that failed: ' || errors);
    FOR i IN 1..errors LOOP      
        DBMS_OUTPUT.PUT_LINE('Error #' || i || ' occurred during '||
        'iteration #' || SQL%BULK_EXCEPTIONS(i).ERROR_INDEX);
        DBMS_OUTPUT.PUT_LINE('Error message is ' ||
        SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
    END LOOP;
  rollback;
END;

 The  row 1 has 1 Updated !
The  row 2 has 1 Updated !
The  row 3 has 1 Updated !
The  row 4 has 1 Updated !
The  row 5 has 1 Updated !
The  row 6 has 1 Updated !
The  row 7 has  no rows Updated !
The  row 8 has 1 Updated !
The  row 9 has 1 Updated !
The  row 10 has 1 Updated !
The  row 11 has 1 Updated !
The  row 12 has 1 Updated !
The  row 13 has  no rows Updated !
Number of statements that failed: 2
Error #1 occurred during iteration #7
Error message is ORA-12899: value too large for column  (actual: , maximum: )
Error #2 occurred during iteration #13
Error message is ORA-12899: value too large for column  (actual: , maximum: )

        
               
从例子可以看出,sql%bulk_rowcount表示的是每一个sql语句影响到多少行。元素个数等于循环数.
                                            sql%bulk_exceptions
则存储了有错误发生的行的信息,实际的bulk_exceptions的元素
                                          
个数等于错误个数。
         5.2 
BULK COLLECT 从查询结果中提取数据到集合中
               
关于这个没有什么特别好说明。就是一个returning语句稍微介绍一下:
                DELETE FROM emp_temp WHERE department_id = 30  RETURNING employee_id, last_name BULK
                       COLLECT INTO enums, names;
               
其次就是可以使用limit语句,以免内存过载.
               
第三,FORALLbulk collect into 可以结合起来,但是SELECT ...BULK COLLECT除外,也就是说只能
                          
returning.
               
        
六,编写精壮计算程序
        
pls_integerbinary_integer做整数运算,用BINARY_FLOATBINARY_DOUBLE做浮点运算。
        
        
七,使用execute immediate cursor变量来调整性能
        
尽量不要用dbms_sql来执行动态sql了(个人任务这个包过时的可能性比较大),现在用execute immedaite
 
够很好的执行各种动态的sql,关于这个可以参考我的另外一篇文章:动态执行sql的几个方式     
         DBMS_SQL
的速度和紧凑性上都比execute immediate来的差。
        
       
,在过程调用中使用NOCOPY编译提示指令
        IN/OUT
的过程传参,一般情况是按值来进行的,这就是说在调用子过程前,需要一个中间变量,然后把值复制给这个中间变量,临了还要拷贝回来,如果参数的数据许多且结构复杂,那么可能就需要消耗许多的时间。
       
使用NOCOPY指令,这样可以强制调用过程的时候使用地址传递参数。这样的好处是快,但是也有个坏处,如果子程序异常结束了,那么参数也可能发生了改变。
        
例子:
         DECLARE

    TYPE EmpTabTyp IS TABLE OF employees%ROWTYPE;
    emp_tab EmpTabTyp := EmpTabTyp(NULL); -- initialize
    t1 NUMBER;
    t2 NUMBER;
    t3 NUMBER;
    PROCEDURE get_time (t OUT NUMBER) IS
    BEGIN t := DBMS_UTILITY.get_time; END;
    PROCEDURE do_nothing1 (tab IN OUT EmpTabTyp) IS
    BEGIN NULL; END;
    PROCEDURE do_nothing2 (tab IN OUT
NOCOPY EmpTabTyp) IS
    BEGIN NULL; END;
BEGIN
    SELECT * INTO emp_tab(1) FROM employees WHERE employee_id = 100;
    emp_tab.EXTEND(49999, 1); -- copy element 1 into 2..50000
    get_time(t1);
    do_nothing1(emp_tab); -- pass IN OUT parameter
    get_time(t2);
    do_nothing2(emp_tab); -- pass IN OUT NOCOPY parameter
    get_time(t3);
    DBMS_OUTPUT.PUT_LINE('Call Duration (secs)');
    DBMS_OUTPUT.PUT_LINE('--------------------');
    DBMS_OUTPUT.PUT_LINE('Just IN OUT: ' || TO_CHAR((t2 - t1)/100.0));
    DBMS_OUTPUT.PUT_LINE('With NOCOPY: ' || TO_CHAR((t3 - t2))/100.0);
END;

      
         
限制性(比较常见的):
         
通过DBLINK调用的过程,或者是外部过程例如DLL之类的,那么这个HINT无效。
         
实参需要一个隐式数据转换的

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值