Oracle和#34; WHERE"中的Oracle和可能的常量谓词条款

时间:2012-12-26 17:42:36

标签: oracle null where procedure recompile

我在以下示例代码中遇到了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为null或e.CustomerId = p_customerId)中的”OR“会导致程序性能下降,因为优化程序不会在”CustomerId“列上最佳地使用索引(我希望索引搜索),从而导致扫描而不是寻求。 “CustomerId”的索引有很多不同的值。

使用MSSQL 2008 R2(最新的SP)或MSSQL 2012时,我可以使用“选项(重新编译)”提示查询,这将:

  1. 仅重新编译此查询
  2. 解析所有变量的值(在调用sproc之后它们是已知的)
  3. 用常量替换所有已解析的变量并消除常量 谓词部分
  4. 例如:如果我传递p_customerId = 1000,那么“1000 is null”表达式将始终为false,因此优化器将忽略它。 这会增加一些CPU开销,但它主要用于很少被称为大规模报告的程序,所以这里没有问题。

    在Oracle中有没有办法做到这一点? Dynamic-SQL不是一个选项。

    添加

    相同的过程只是没有“p_customerId为空”而“p_eventTypeId为空”运行~0.041秒,而上层运行~0.448秒(我有~5000.000行)。

2 个答案:

答案 0 :(得分:0)

一个列索引无法帮助,因为它没有存储在索引定义中。 是否允许创建索引(客户ID,事件ID,ID)?这样所有需要的列都在索引...

答案 1 :(得分:0)

CREATE INDEX IX_YOURNAME1 ON eventstable (NVL(p_customerId, 'x'));
CREATE INDEX IX_YOURNAME2 ON eventstable (NVL(p_eventTypeId, 'x'));

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 
        (NVL(p_customerId, 'x') = e.CustomerId OR NVL(p_customerId, 'x') = 'x')
    AND (NVL(p_eventTypeId, 'x') = e.EventTypeId OR NVL(p_eventTypeId, 'x') = 'x')
    order by Id asc;
end usp_test;