动态查询对Native Dynamic SQL的动态绑定

时间:2015-04-24 15:14:22

标签: oracle performance plsql dynamic-binding

我发现自己的情况是我的代码需要执行由未知数字(至少一个,但可能更多)形成的动态语句,其他动态语句由“交叉”连接。和' union'运营商。

这是一个有三个查询的示例(我知道这可以通过一个查询解决,我试图保持简单):

sql1 varchar2(500) := 'select empno from emp where deptno = :1';
sql2 varchar2(500) := 'select empno from emp where sal > :2 and hiredate >=:3'; 
sql3 varchar2(500) := 'select empno from emp where sal <= :2 and hiredate =:3'
realStatement varchar(1500) := sql1 || ' insersect ' || sql2 || ' union ' sql3;

现在,鉴于它在运行时未知的子语句数量,但所有绑定变量值都是已知的(即deptno,sal和hiredate将始终分别为:1,:2和:3 )。我无法使用&#39; EXECUTE IMMEDIATE realStatement USING&#39; form因为它的绑定是位置的,对于这个例子,我应该传递sal和hiredate参数两次,结果是声明:

EXECUTE IMMEDIATE realStatement USING l_deptno,l_sal,l_hiredate,l_sal,l_hiredate;

我事先无法知道包含每个子语句的所有重复。

我知道我可以将DBMS_SQL包与bind()函数一起使用,但其性能比本机动态(来自oracle docs)差1.5到3倍,并且在这种情况下性能是相关的。

所以我实际上正在做的是取代所有的&#39; 1&#39;发生在l_deptno,所有&#39;:2&#39;与l_sal一起出现,以及所有&#39;:3&#39;发生在&#39; to_date(&#39;&#39; || l_hiredate ||&#39;&#39;&#39;&#39;&#39; DD / MM / YYYY&#39;&#39;)&#39;在执行它之前的realStatement字符串中,如下所示:

realStatement := replace(realStatement,':1',l_deptno);
realStatement := replace(realStatement,':2',l_sal);
realStatement := replace(realStatement,':3','to_date(''' || l_hiredate || ''',''DD/MM/YYYY'')');
EXECUTE IMMEDIATE realStatement;

但我不确定这是最好的解决方案,问题:

  1. 有没有办法提高性能或传递绑定 动态使用本机动态SQL?

  2. 使用DBSM_SQL包会带来更好的性能 比选择的解决方案?

3 个答案:

答案 0 :(得分:1)

重写你的陈述:

sql1 varchar2(500) := 'select empno from emp where deptno = :1';
sql2 varchar2(500) := 'select empno from emp where sal > :2 and hiredate >=:3'; 
sql3 varchar2(500) := 'select empno from emp where sal <= :2 and hiredate =:3'
realStatement varchar(1500) := sql1 || ' insersect ' || sql2 || ' union ' sql3;

利用WITH条款如下:

sql0 varchar2(500) := 'WITH par AS (SELECT :1 AS P1, :2 AS P2, :3 AS P3 FROM dual)';
sql1 varchar2(500) := '(select empno from emp join par where deptno = par.p1)';
sql2 varchar2(500) := '(select empno from emp join par where sal > par.p2 and hiredate >=par.p3)'; 
sql3 varchar2(500) := '(select empno from emp join par where sal <= par.p2 and hiredate = par.p3)';
realStatement varchar(2000) := sql0 || ', sql1 as ' || sql1 || ', sql2 as ' || sql2 || ', sql3 as ' || sql3 || ' select * from sql1 intersect select * from sql2 union select * from sql3';

或(当没有重用子查询时):

sql0 varchar2(500) := 'WITH par AS (SELECT :1 AS P1, :2 AS P2, :3 AS P3 FROM dual)';
sql1 varchar2(500) := 'select empno from emp join par where deptno = par.p1';
sql2 varchar2(500) := 'select empno from emp join par where sal > par.p2 and hiredate >=par.p3'; 
sql3 varchar2(500) := 'select empno from emp join par where sal <= par.p2 and hiredate = par.p3';
realStatement varchar(2000) := sql0 || ' ' || sql1 || ' intersect ' || sql2 || ' union ' || sql3;

然后使用3个绑定变量执行它:EXECUTE IMMEDIATE realStatement USING l_deptno,l_sal,l_hiredate

答案 1 :(得分:0)

正如您已经提到的,Oracle文档(http://docs.oracle.com/cd/B19306_01/appdev.102/b14251/adfns_dynamic_sql.htm#BJEBACEH)说:

  

使用本机动态SQL的程序比使用DBMS_SQL程序包的程序快得多。通常,本机动态SQL语句的执行速度比等效的DBMS_SQL调用好1.5到3倍。

但是从另一方面 - 你可以在这里看到一些比较:http://www.toadworld.com/products/toad-for-oracle/w/toad_for_oracle_wiki/231.dbms-sql-vs-execute-immediate.aspx

  

使用DBMS_SQL优于EXECUTE IMMEDIATE:

     
      
  • 拼写和打字更容易(对我来说无论如何 - 我无法拼写IMMEDAITE IMMADIATE立即

  •   
  • 使用DBMS_SQL减少锁定。

  •   
  • 使用DBMS_SQL解析的次数减少。

  •   
  • 由于上述原因,使用DBMS_SQL可以更好地扩展您的应用程序。

  •   
     

缺点:

     
      
  • 使用DBMS_SQL进行更多输入。
  •   

我想说 - 如果你有很多这样的调用,那么绑定变量和减少解析计数将产生重大影响。但是 - 如果你没有多次调用而单个查询返回很多行 - 那么在没有绑定变量的情况下执行IMMEDIATE(你的解决方案可以更快)。

在任何情况下 - 如果性能相关 - 制作两个解决方案(使用EXECUTE IMMEDIATE和DBMS_SQL)并比较结果。

答案 2 :(得分:0)

几年前,当我参加培训时,性能差异是一个主题(它是Oracle 9i)。我们能够重现差异。但是,当我今天进行相同的测试时(使用Oracle 11),我不再有任何性能差异了。使用对您来说更方便的方式。