PL SQL - select语句的where子句中的动态SQL

时间:2013-06-18 15:38:35

标签: sql performance oracle plsql dynamic-sql

我是Oracle PL / SQL的新手,但在Sql Server中经验丰富,我正在努力学习它的来龙去脉。为了介绍它,我决定优化一个生成为C#字符串的查询,然后作为文本SqlCommand执行。所以我试图创建一个存储过程,但是要包含where子句如何生成的所有变量,它会导致它运行~40秒,同时C#生成的字符串在~3秒内执行。以下是where子句变体的含义示例...

declare  
searchType nvarchar2(3); -- options are 'x', 'y', 'z'  
searchDesc nvarchar2(4); -- options are '1', '2', '3'  
searchValue nvarchar2(5);

begin  

select count(*)  
from tbl_A a
where ((searchType = 'x' 
    and ((a.desc_X = searchDesc and a.value_1 = searchValue)
      or (a.desc_X = searchDesc and a.value_2 = searchValue)
      or (a.desc_X = searchDesc and a.value_3 = searchValue)
    )
  )
  or (searchType = 'y' 
    and ((a.desc_Y = searchDesc and a.value_1 = searchValue)
      or (a.desc_Y = searchDesc and a.value_2 = searchValue)
      or (a.desc_Y = searchDesc and a.value_3 = searchValue)
    )
  )
  or (searchType = 'z' 
    and ((a.desc_Z = searchDesc and a.value_1 = searchValue)
      or (a.desc_Z = searchDesc and a.value_2 = searchValue)
      or (a.desc_Z = searchDesc and a.value_3 = searchValue)
    )
  )
)

end;

所以我想知道的是,是否有可能在where子句中有一个可以执行动态sql的select语句。或者整个语句需要是动态sql。以下是我正在质疑的一个例子......

declare
whereClause varchar2(500);  
searchType nvarchar2(3); -- options are 'x', 'y', 'z'  
searchDesc nvarchar2(4); -- options are '1', '2', '3'  
searchValue nvarchar2(5);  

begin

select case
    when searchType = 'x' then 'a.desc_X = :desc and a.value_1 = :val'
    when searchType = 'y' then 'a.desc_Y = :desc and a.value_2 = :val'
    when searchType = 'z' then 'a.desc_Z = :desc and a.value_3 = :val'
    end
into whereClause
from dual;

select count(*)
from tbl_A a
where (
    execute immediately whereClause using searchDesc, searchValue
)

end;

当我尝试将其作为所有动态sql执行时,它仍然需要大约15秒才能执行。因此,如果有人有更好的方法来处理许多where子句的变化,我愿意接受建议。

1 个答案:

答案 0 :(得分:2)

使用过多的OR会导致性能下降。如果你总是要有一组固定的参数,你可以这样做:

declare

    stmt varchar2(1500);  
    searchType nvarchar2(3); -- options are 'x', 'y', 'z'  
    searchDesc nvarchar2(4); -- options are '1', '2', '3'  
    searchValue nvarchar2(5);  

    n pls_integer;

begin

    stmt := 'select count(*) from tbl_A a where (';

     case
        when searchType = 'x' then stmt := stmt || 'a.desc_X = :desc and a.value_1 = :val';
        when searchType = 'y' then stmt := stmt || 'a.desc_Y = :desc and a.value_2 = :val';
        when searchType = 'z' then stmt := stmt || 'a.desc_Z = :desc and a.value_3 = :val';
    end case;

    stmt := stmt ||')';


    execute immediately stmt using searchDesc, searchValue
    into n;

end;

请注意 - 与T-SQL不同 - 在PL / SQL中,我们需要将结果集选择为变量。我提出了一个整数,因为你的示例代码只是SELECT COUNT(*)。您的真实查询将需要一个与查询投影匹配的变量,可能是记录类型或集合。