Oracle 在PL\SQL中使用具有空值的变量的动态游标
有人能帮我解决这个问题吗? 我有一个如下定义的游标:Oracle 在PL\SQL中使用具有空值的变量的动态游标,oracle,plsql,oracle11g,Oracle,Plsql,Oracle11g,有人能帮我解决这个问题吗? 我有一个如下定义的游标: CURSOR c_cursorName ( paramA IN VARCHAR2, paramB IN VARCHAR2) IS SELECT tableA.id, tableA.name FROM tableA WHERE tableA.fieldA = paramA AND (paramB IS NULL OR tableA
CURSOR c_cursorName (
paramA IN VARCHAR2,
paramB IN VARCHAR2)
IS
SELECT tableA.id, tableA.name
FROM tableA
WHERE tableA.fieldA = paramA
AND (paramB IS NULL OR tableA.fieldB = paramB);
我为什么要这么做?因为我想在两种不同的情况下重用此游标:
null
value)时,我想返回tableA中的所有行,其中fieldA等于paramA(我不关心fieldB)李>
问题是:当我在paramB中通过null
时,我的解释计划会急剧增加,并且会出现性能问题
实现这一点的简单方法是创建两个不同的游标,每种情况一个。但我正试图找到一个好的、聪明的解决方案,而不需要创建新的索引或游标
有什么建议吗?你可以试试:
cursor c_cursorname (parama in varchar2,
paramb in varchar2)
is
with results as (select tablea.id,
tablea.name,
tablea.fieldb
from tablea
where tablea.fielda = parama)
select id, name
from results
where paramb is null
union all
select id, name
from results
where fieldb = paramb;
Oracle应该能够根据paramb的值短路union all中运行的两个查询中的哪一个。您可以尝试:
cursor c_cursorname (parama in varchar2,
paramb in varchar2)
is
with results as (select tablea.id,
tablea.name,
tablea.fieldb
from tablea
where tablea.fielda = parama)
select id, name
from results
where paramb is null
union all
select id, name
from results
where fieldb = paramb;
Oracle应该能够根据paramb的值短路union all中运行的两个查询中的哪一个。一个基于@Boniest的“独占union all”方法的稍加修改的解决方案: 我不使用子查询来避免可能的物化,而是添加显式查询 检查paramb的NULL/notnull以始终仅执行UNION ALL的一部分
SELECT tableA.id, tableA.name
FROM tableA
WHERE tableA.fieldA = :parama
AND :paramb IS NULL
UNION ALL
SELECT tableA.id, tableA.name
FROM tableA
WHERE tableA.fieldA = :parama
AND :paramb IS NOT NULL
AND fieldb = :paramb
我假设表A上有一个索引(fieldA,fieldB)
这将导致下面的执行计划
对于paramb为空
fieldA上的索引范围扫描已完成
对于paramb不为空
fieldA上的索引范围扫描,fieldB已完成
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 101 | 4962 | 5 (40)| 00:00:01 |
| 1 | UNION-ALL | | | | | |
|* 2 | FILTER | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| TABLEA | 100 | 4900 | 3 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | TABLEA_IDX1 | 40 | | 2 (0)| 00:00:01 |
|* 5 | FILTER | | | | | |
| 6 | TABLE ACCESS BY INDEX ROWID| TABLEA | 1 | 62 | 2 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | TABLEA_IDX1 | 1 | | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SET$1
2 - SEL$1
3 - SEL$1 / TABLEA@SEL$1
4 - SEL$1 / TABLEA@SEL$1
5 - SEL$2
6 - SEL$2 / TABLEA@SEL$2
7 - SEL$2 / TABLEA@SEL$2
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(:PARAMB IS NULL)
4 - access("TABLEA"."FIELDA"=TO_NUMBER(:PARAMA))
5 - filter(:PARAMB IS NOT NULL)
7 - access("TABLEA"."FIELDA"=TO_NUMBER(:PARAMA) AND "FIELDB"=TO_NUMBER(:PARAMB))
基于@Boniest: 我不使用子查询来避免可能的物化,而是添加显式查询 检查paramb的NULL/notnull以始终仅执行UNION ALL的一部分
SELECT tableA.id, tableA.name
FROM tableA
WHERE tableA.fieldA = :parama
AND :paramb IS NULL
UNION ALL
SELECT tableA.id, tableA.name
FROM tableA
WHERE tableA.fieldA = :parama
AND :paramb IS NOT NULL
AND fieldb = :paramb
我假设表A上有一个索引(fieldA,fieldB)
这将导致下面的执行计划
对于paramb为空
fieldA上的索引范围扫描已完成
对于paramb不为空
fieldA上的索引范围扫描,fieldB已完成
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 101 | 4962 | 5 (40)| 00:00:01 |
| 1 | UNION-ALL | | | | | |
|* 2 | FILTER | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| TABLEA | 100 | 4900 | 3 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | TABLEA_IDX1 | 40 | | 2 (0)| 00:00:01 |
|* 5 | FILTER | | | | | |
| 6 | TABLE ACCESS BY INDEX ROWID| TABLEA | 1 | 62 | 2 (0)| 00:00:01 |
|* 7 | INDEX RANGE SCAN | TABLEA_IDX1 | 1 | | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SET$1
2 - SEL$1
3 - SEL$1 / TABLEA@SEL$1
4 - SEL$1 / TABLEA@SEL$1
5 - SEL$2
6 - SEL$2 / TABLEA@SEL$2
7 - SEL$2 / TABLEA@SEL$2
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(:PARAMB IS NULL)
4 - access("TABLEA"."FIELDA"=TO_NUMBER(:PARAMA))
5 - filter(:PARAMB IS NOT NULL)
7 - access("TABLEA"."FIELDA"=TO_NUMBER(:PARAMA) AND "FIELDB"=TO_NUMBER(:PARAMB))
两种解决方案都很棒!但我有一个性能问题,因为我需要在这里处理实际表中的索引(当然,表A不存在)。谢谢两种解决方案都很棒!但我有一个性能问题,因为我需要在这里处理实际表中的索引(当然,表A不存在)。谢谢