我有一个存储过程,它从Json结构中获取可选参数。如果提供了json值,则参数将用作游标的条件。如果没有提供json值,我不希望出现这种情况。 我已经通过在sql条件中使用Coalesce / Nvl解决了这个问题。问题是该过程使用Nvl / Coalesce运行了很长时间。我可以使用哪种方法更有效率吗?也许是动态的sql?
我的程序:
Create or Replace Procedure findaccounts
(jsonIn IN clob,
jsonOut OUT varchar2)
As
obj json := json(jsonIn);
json_obj_out json;
json_lst json_list := json_list();
--Getstring is a function that sets variable to null if json value is not found
istatus varchar2(10) := GetString(obj json, 'status');
icreatedate := GetString(obj json, 'daysold');
iage int := GetString(obj json, 'age');
irownum int := GetString(obj json, 'rownum');
Begin
For rec in (Select A.accountnumber
From Accounts A
Inner Join Accountowner Ao On A.ownerId = Ao.Id
Where A.Status = iStatus
And A.daysold >= Coalesce(idaysold,A.daysold)
And Ao.Age = Coalesce(iAge,Ao.Age)
And rownum <= Coalesce(iRownum,5))
loop
obj := json();
obj.put('accountnumber',Rec.accountnumber);
json_lst.append(obj.to_json_value);
end loop;
json_lst.print;
jsonOut := json_lst.to_char();
End;
动态sql提升了性能。具有动态绑定变量的选项通过dbms_sql包解析,因为execute immediate没有此选项。
答案 0 :(得分:2)
从功能上讲,Coalesce
是处理可选搜索条件的好方法。
从表现来看,这并不好。优化器无法有效优化,因为它只决定执行计划一次,优化了第一次运行SQL时提供的搜索条件。
如果需要不同的执行计划来获得可接受的性能,那么您需要为这些不同的搜索模式使用不同的SQL语句。
以下是我过去使用的两种不同解决方案:
创建几个不同的SQL:s,每个SQL处理将共享相同执行计划的可能搜索条件的子集。在您的情况下,您可以在iAge
为null
时使用其中一个,idaysold
为null
时为另一个,null
时为三分之一。
使用动态SQL。
答案 1 :(得分:0)
您可以删除COALESCE()
这样的功能:
And ( idaysold IS NULL OR A.daysold >= idaysold )
And ( iAge IS NULL OR Ao.Age = iAge )
And ( ( iRownum IS NULL AND ROWNUM <= 5 ) OR rownum <= iRownum )
答案 2 :(得分:0)
NVL
通常是通过可选参数进行过滤的最有效方法。它的效果通常优于COALESCE
,OR
,CASE
,DECODE
以及其他类似的解决方案。
切换回该方法,如果效果不佳,可能会出现其他一些潜在问题。查找该语句的解释计划或SQL监视报告,并在此处发布以获取进一步的建议。
NVL
通常效果最好,因为它最有可能创建CONCATENATION
和FILTER
次操作。 (请注意,FILTER
操作与解释计划底部的Filter
部分不同。)这些操作允许Oracle创建两个不同的执行计划并在运行时间取决于绑定变量。
理想情况下,解释计划看起来像这样:
----------------------------------------------------
| Id | Operation | Name |
----------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | CONCATENATION | |
| 2 | FILTER | |
| 3 | TABLE ACCESS FULL | MYTABLE |
| 4 | FILTER | |
| 5 | TABLE ACCESS BY INDEX ROWID| MYTABLE |
| 6 | INDEX UNIQUE SCAN | MYTABLE_PK |
----------------------------------------------------
请参阅我的回答here,查看演示NVL
如何运作的测试脚本。
我认为您的代码有可能存在两个不幸的问题。如果没有NVL
,它将不会生成单独的执行计划。使用NVL
它可能会产生两个计划,但也许两个计划都很糟糕。即使NVL
也不会产生单独的计划,我建议你看看KlasLindbäck的答案。