PL SQL—select语句where子句中的动态SQL
我对Oracle PL/SQL非常陌生,但对SQL Server很有经验,我正在尝试了解它的来龙去脉。作为对它的介绍,我决定优化一个查询,该查询生成为C字符串,然后作为文本命令执行。因此,我试图创建一个存储过程,但为了包含where子句生成方式的所有变化,它使它运行约40秒,而C生成的字符串在约3秒内执行。下面是一个例子,我所说的where子句的变体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
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代码目前正在这样做,这将使复杂性从一个环境转移到另一个环境。谢谢你的帮助。我会给这个问题多一点时间来烹饪,然后再把这个问题作为答案,看看还会出现什么。