在以下示例代码中,我对 ORACLE 有一个常见问题:
create or replace procedure usp_test
(
p_customerId number,
p_eventTypeId number,
p_out OUT SYS_REFCURSOR
)
as
begin
open p_out for
select e.Id from eventstable e
where
(p_customerId is null or e.CustomerId = p_customerId)
and
(p_eventTypeId is null or e.EventTypeId = p_eventTypeId)
order by Id asc;
end usp_test;
"(p_customerId is null or e.CustomerId = p_customerId)" 中的 "OR" 会破坏程序性能,因为优化器不会在 "CustomerId" 列上最佳地使用索引(我希望索引搜索),从而导致扫描而不是搜索。“CustomerId”上的索引有很多不同的值。
使用 MSSQL 2008 R2(最新 SP)或 MSSQL 2012 时,我可以使用“选项(重新编译)”提示查询,这将:
- 仅重新编译此查询
- 解析所有变量的值(在调用 sproc 后它们是已知的)
- 用常量替换所有解析的变量并消除常量谓词部分
例如:如果我通过 p_customerId = 1000,那么“1000 is null”表达式将始终为假,因此优化器将忽略它。这会增加一些 CPU 开销,但它主要用于很少调用的海量报告程序,所以这里没有问题。
有没有办法在 Oracle 中做到这一点?动态 SQL 不是一个选项。
添加
没有“p_customerId 为空”和“p_eventTypeId 为空”的相同程序运行约 0.041 秒,而上一个运行约 0.448 秒(我有约 5.000.000 行)。