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

Dynamic binding for dynamic query on Native Dynamic SQL

我发现自己处于一种情况,我的代码需要执行由 'intersect' 和 [=39 连接的未知数量(至少一个,但可能更多)的其他动态语句组成的动态语句=] 运算符。

这是一个包含三个查询的示例(我知道这可以通过一个查询解决,我尽量保持简单):

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分别)。我不能使用 'EXECUTE IMMEDIATE realStatement USING' 形式,因为它的绑定是位置性的,对于这个例子,我应该两次传递 sal 和 hiredate 参数,结果是语句:

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

我不可能事先知道包含每个子语句的所有重复项。

我知道我可以将 DBMS_SQL 包与 bind() 函数一起使用,但性能比原生动态(来自 oracle 文档)差 1.5 到 3 倍,在这种情况下性能是相关。

所以我实际做的是用 l_deptno 替换所有出现的 ':1',用 l_sal 替换所有出现的 ':2',以及用 l_sal 替换所有出现的 ':3' 'to_date(''' || l_hiredate || ''',''DD/MM/YYYY'')' 在 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 包会带来更好的性能吗 比选择的解决方案?

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

Programs that use native dynamic SQL are much faster than programs that use the DBMS_SQL package. Typically, native dynamic SQL statements perform 1.5 to 3 times better than equivalent DBMS_SQL calls.

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

There are many advantages to using DBMS_SQL over EXECUTE IMMEDIATE :

  • It's easier to spell and type (for me anyway - I can't spell IMMEDAITE IMMEADIATE IMMEDIATE

  • Less latching with DBMS_SQL.

  • Fewer parses with DBMS_SQL.

  • Better scaling of your app with DBMS_SQL because of the above.

Disadvantages :

  • More typing overall with DBMS_SQL.

我想说 - 如果您有很多这样的调用,那么绑定变量和减少解析计数将产生重大影响。但是 - 如果你没有很多调用和单个查询 returns 很多行 - 那么没有绑定变量的 EXECUTE IMMEDIATE(你的替换解决方案)会更快。

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

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

重写你的陈述:

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