4、在动态SQL中是使用绑定变量   

[sql] view plaincopyprint?
-->动态SQL中不能自动使用绑定变量,需要手动设定绑定变量                                                                   
SQL> @get_parse     -->获得当前hard parse解析情况,此时为120                                                             
                                                                                                                        
NAME                           VALUE                                                                                    
------------------------- ----------                                                                                     
parse count (total)              533                                                                                    
parse count (hard)               120                                                                                    
parse count (failures)             1                                                                                    
                                                                                                                        
SQL> begin                                                                                                              
  2  for i in 1..30 loop                                                                                                
  3  execute immediate 'insert into t values(:1,:2)' using i,i+i-2;  -->动态SQL使用绑定变量,该语句将执行30次            
  4  end loop;                                                                                                          
  5  commit;                                                                                                            
  6  end;                                                                                                               
  7  /                                                                                                                  
                                                                                                                        
PL/SQL procedure successfully completed.                                                                                
                                                                                                                        
SQL> @get_parse     --> 动态SQL执行后,尽管执行了30次,但硬解析数量仅仅增加了2次                                         
                                                                                                                        
NAME                           VALUE                                                                                    
------------------------- ----------                                                                                     
parse count (total)              537                                                                                    
parse count (hard)               122                                                                                    
parse count (failures)             1                                                                                    
                                                                                                                        
SQL> set serveroutput on;                                                                                               
SQL> get get_sal.sql    -->下面的pl/sql中使用了绑定变量                                                                  
  1   DECLARE                                                                                                           
  2   TYPE emp_cur IS REF CURSOR;                                                                                       
  3   my_emp_cur emp_cur;                                                                                               
  4   my_emp_rec emp%ROWTYPE;                                                                                           
  5   BEGIN                                                                                                             
  6   OPEN my_emp_cur FOR 'select * from emp where deptno=:dno' USING 10;                                               
  7   LOOP                                                                                                              
  8   FETCH my_emp_cur INTO my_emp_rec;                                                                                 
  9   EXIT WHEN my_emp_cur%NOTFOUND;                                                                                    
 10   dbms_output.put_line(my_emp_rec.ename||'''s salary is : '||my_emp_rec.sal);                                       
 11   END LOOP;                                                                                                         
 12*  END;                                                                                                              
 13  /                                                                                                                  
CLARK's salary is : 4900                                                                                                
KING's salary is : 5000                                                                                                 
MILLER's salary is : 1300                                                                                               
                                                                                                                        
PL/SQL procedure successfully completed.                                                                                
                                                                                                                        
SQL> /                                                                                                                  
CLARK's salary is : 4900                                                                                                
KING's salary is : 5000                                                                                                 
MILLER's salary is : 1300                                                                                               
                                                                                                                        
PL/SQL procedure successfully completed.                                                                                
                                                                                                                        
SQL> select sql_text,executions,sql_id from v$sqlarea where sql_text like 'select * from emp where deptno=:dno%';       
                                                                                                                        
SQL_TEXT                                      EXECUTIONS SQL_ID                                                         
--------------------------------------------- ---------- -------------                                                   
select * from emp where deptno=:dno                    2 c1nx6x02h655a                                                  
-->动态SQL中不能自动使用绑定变量,需要手动设定绑定变量                                                                
SQL> @get_parse     -->获得当前hard parse解析情况,此时为120                                                          
                                                                                                                      
NAME                           VALUE                                                                                  
------------------------- ----------                                                                                  
parse count (total)              533                                                                                  
parse count (hard)               120                                                                                  
parse count (failures)             1                                                                                  
                                                                                                                      
SQL> begin                                                                                                            
  2  for i in 1..30 loop                                                                                              
  3  execute immediate 'insert into t values(:1,:2)' using i,i+i-2;  -->动态SQL使用绑定变量,该语句将执行30次         
  4  end loop;                                                                                                        
  5  commit;                                                                                                          
  6  end;                                                                                                             
  7  /                                                                                                                
                                                                                                                      
PL/SQL procedure successfully completed.                                                                              
                                                                                                                      
SQL> @get_parse     --> 动态SQL执行后,尽管执行了30次,但硬解析数量仅仅增加了2次                                      
                                                                                                                      
NAME                           VALUE                                                                                  
------------------------- ----------                                                                                  
parse count (total)              537                                                                                  
parse count (hard)               122                                                                                  
parse count (failures)             1                                                                                  
                                                                                                                      
SQL> set serveroutput on;                                                                                             
SQL> get get_sal.sql    -->下面的pl/sql中使用了绑定变量                                                               
  1   DECLARE                                                                                                         
  2   TYPE emp_cur IS REF CURSOR;                                                                                     
  3   my_emp_cur emp_cur;                                                                                             
  4   my_emp_rec emp%ROWTYPE;                                                                                         
  5   BEGIN                                                                                                           
  6   OPEN my_emp_cur FOR 'select * from emp where deptno=:dno' USING 10;                                             
  7   LOOP                                                                                                            
  8   FETCH my_emp_cur INTO my_emp_rec;                                                                               
  9   EXIT WHEN my_emp_cur%NOTFOUND;                                                                                  
 10   dbms_output.put_line(my_emp_rec.ename||'''s salary is : '||my_emp_rec.sal);                                     
 11   END LOOP;                                                                                                       
 12*  END;                                                                                                            
 13  /                                                                                                                
CLARK's salary is : 4900                                                                                              
KING's salary is : 5000                                                                                               
MILLER's salary is : 1300                                                                                             
                                                                                                                      
PL/SQL procedure successfully completed.                                                                              
                                                                                                                      
SQL> /                                                                                                                
CLARK's salary is : 4900                                                                                              
KING's salary is : 5000                                                                                               
MILLER's salary is : 1300                                                                                             
                                                                                                                      
PL/SQL procedure successfully completed.                                                                              
                                                                                                                      
SQL> select sql_text,executions,sql_id from v$sqlarea where sql_text like 'select * from emp where deptno=:dno%';     
                                                                                                                      
SQL_TEXT                                      EXECUTIONS SQL_ID                                                       
--------------------------------------------- ---------- -------------                                                
select * from emp where deptno=:dno                    2 c1nx6x02h655a                                                
 
       
三、绑定变量的优缺点及使用场合
    优点:
        可以在library cache中共享游标,避免硬解析以及与之相关的额外开销
        在大批量数据操作时将呈数量级来减少闩锁的使用,避免闩锁的竞争
     
    缺点:
        绑定变量被使用时,查询优化器会忽略其具体值,因此其预估的准确性远不如使用字面量值真实,尤其是在表存在数据倾斜(表上的数
        据非均匀分布)的列上会提供错误的执行计划。从而使得非高效的执行计划被使用。
   
    使用场合:
        OLTP
            在OLTP系统中SQL语句重复执行频度高,但处理的数据量较少,结果集也相对较小,尤其是使用表上的索引来缩小中间结果集,其
            解析时间通常会接近或高于执行时间,因此该场合适合使用绑定变量。
       
        OLAP
            在OLAP系统中,SQL语句执行次数相对较少,但返回的数据量较大,因此多数情况下倾向于使用权标扫描更高效,其SQL语句执行时
            间远高于其解析时间,因此使用绑定变量对于总响应时间影响不大。而且增加生成低效执行计划的风险。即在在OLAP系统中使用字
            面量的性能高于使用绑定变量。
   
    注意:
        对于实际的数据库对象,如(表,视图,列等),不能使用绑定变量替换,只能替换字面量。如果对象名是在运行时生成的,则需要对其
        用字符串拼接,同时,sql只会匹配已经在共享池中相同的对象名。