我发现自己的情况是我的代码需要执行由未知数字(至少一个,但可能更多)形成的动态语句,其他动态语句由“交叉”连接。和' 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;
但我不确定这是最好的解决方案,问题:
有没有办法提高性能或传递绑定 动态使用本机动态SQL?
使用DBSM_SQL包会带来更好的性能 比选择的解决方案?
答案 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),我不再有任何性能差异了。使用对您来说更方便的方式。