Oracle where条件中的可选参数-如何提高性能-PL/SQL
我有一个从Json结构中获取可选参数的存储过程。如果提供了json值,参数将用作游标的条件。如果没有提供json值,我不希望出现这种情况。 我通过在sql条件下使用Coalesce/Nvl解决了这个问题。问题是该过程使用Nvl/Coalesce运行了很长时间。有没有其他更有效的方法?也许是动态sql 我的程序:Oracle where条件中的可选参数-如何提高性能-PL/SQL,oracle,oracle11g,pljson,Oracle,Oracle11g,Pljson,我有一个从Json结构中获取可选参数的存储过程。如果提供了json值,参数将用作游标的条件。如果没有提供json值,我不希望出现这种情况。 我通过在sql条件下使用Coalesce/Nvl解决了这个问题。问题是该过程使用Nvl/Coalesce运行了很长时间。有没有其他更有效的方法?也许是动态sql 我的程序: Create or Replace Procedure findaccounts (jsonIn IN clob, jsonOut OUT varchar2) As obj j
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没有此选项 您可以像这样消除合并函数:
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 )
----------------------------------------------------
| 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 |
----------------------------------------------------
从功能上讲,联合是处理可选搜索条件的一种很好的方法。
性能不好。优化程序将无法有效地进行优化,因为它只决定一次执行计划,优化第一次运行SQL时提供的搜索条件
如果需要不同的执行计划来获得可接受的性能,那么您需要为这些不同的搜索模式使用不同的SQL语句
以下是我过去使用过的两种不同的解决方案:
创建多个不同的SQL:s,其中每个SQL:s处理共享同一执行计划的可能搜索条件的子集。在您的例子中,可以在iAge为null时使用一个,在idaysold为null时使用另一个,在两者都不为null时使用第三个
使用动态SQL
NVL通常是通过可选参数进行过滤的最有效方法。它通常会比联合、或CASE、DECODE和其他类似的解决方案表现得更好
切换回该方法,如果它不能正常工作,则可能存在其他潜在问题。找到该语句的解释计划或SQL监控报告,并将其发布在此处以获取进一步建议
NVL通常工作得最好,因为它最有可能创建串联和过滤操作。请注意,筛选器操作与解释计划底部的筛选器部分不同。这些操作允许Oracle创建两个不同的执行计划,并在运行时根据绑定变量选择一个执行计划
理想情况下,解释计划应如下所示:
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 )
----------------------------------------------------
| 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 |
----------------------------------------------------
有关演示NVL如何工作的测试脚本,请参阅我的答案
我认为你的代码可能有两个不幸的问题。如果没有NVL,它将不会生成单独的执行计划。使用NVL可能会生成两个计划,但这两个计划可能都不好。Ff即使是NVL也不会生成单独的计划,那么我建议您研究一下Klas Lindbäck的答案。在WHERE子句中使用函数可能意味着使用基于函数的索引或不使用索引而不是列索引。在这个版本中,没有函数,如果存在列索引,应该使用列索引-OP可以对这两个查询运行解释计划,并查看所使用的索引是否有差异。我认为Oracle优化器会在将其交给优化器之前查看coalesce/nvl并对其进行扩展。这将需要巨大的性能打动态SQL或表函数似乎是处理多参数hanks的唯一方法。问题通过dbms_sql解决。我找不到一种通过executeimmediate拥有可选绑定变量的方法。