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

PL SQL—select语句where子句中的动态SQL,sql,performance,oracle,plsql,dynamic-sql,Sql,Performance,Oracle,Plsql,Dynamic Sql,我对Oracle PL/SQL非常陌生,但对SQL Server很有经验,我正在尝试了解它的来龙去脉。作为对它的介绍,我决定优化一个查询,该查询生成为C字符串,然后作为文本命令执行。因此,我试图创建一个存储过程,但为了包含where子句生成方式的所有变化,它使它运行约40秒,而C生成的字符串在约3秒内执行。下面是一个例子,我所说的where子句的变体 declare searchType nvarchar2(3); -- options are 'x', 'y', 'z' searchD

我对Oracle PL/SQL非常陌生,但对SQL Server很有经验,我正在尝试了解它的来龙去脉。作为对它的介绍,我决定优化一个查询,该查询生成为C字符串,然后作为文本命令执行。因此,我试图创建一个存储过程,但为了包含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子句中使用select语句来执行动态sql。或者整个语句需要是动态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子句的变化,我愿意接受建议。

像那样使用过多的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中,我们需要将结果集选择到一个变量中。我提出了一个整数,因为您的示例代码是selectcount*。真正的查询需要一个与查询投影匹配的变量,可能是记录类型或集合。

至于您的问题,整个语句是否需要是动态sql,答案是肯定的。根据您的第一个过程示例以及C生成的版本和proc之间的时间差,我猜proc版本中的WHERE子句正在扼杀任何优化的机会-可能C版本有一个更具针对性的WHERE子句。您可以尝试复制过程中的C逻辑,并对生成的字符串立即执行,但我怀疑这会给您带来很大的提升。在这种情况下,你可能需要在别处寻找优化。是的,我想这可能是你必须要做的事情。我试图避免将查询的所有部分都包含在一个字符串中,因为C代码目前正在这样做,这将使复杂性从一个环境转移到另一个环境。谢谢你的帮助。我会给这个问题多一点时间来烹饪,然后再把这个问题作为答案,看看还会出现什么。