3

在以下示例代码中,我对 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 时,我可以使用“选项(重新编译)”提示查询,这将:

  1. 仅重新编译此查询
  2. 解析所有变量的值(在调用 sproc 后它们是已知的)
  3. 用常量替换所有解析的变量并消除常量谓词部分

例如:如果我通过 p_customerId = 1000,那么“1000 is null”表达式将始终为假,因此优化器将忽略它。这会增加一些 CPU 开销,但它主要用于很少调用的海量报告程序,所以这里没有问题。

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

添加

没有“p_customerId 为空”和“p_eventTypeId 为空”的相同程序运行约 0.041 秒,而上一个运行约 0.448 秒(我有约 5.000.000 行)。

4

2 回答 2

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;
于 2012-12-26T19:32:16.773 回答
0

一列索引无济于事,因为它没有存储在索引定义中。是否允许在 (customer id, event id, id ) 上创建索引?这样所有需要的列都在索引中......

于 2012-12-26T18:14:04.507 回答