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がnullまたはe.CustomerId = p_customerId)」の「OR」は、オプティマイザが「CustomerId」列のインデックス(インデックスシークを希望)を最適に使用せず、シークではなくスキャンが発生するため、プロシージャのパフォーマンスを低下させます。「CustomerId」のインデックスには、明確な値がたくさんあります。

MSSQL 2008 R2(最新のSP)またはMSSQL 2012を使用している場合、「option(recompile)」を使用してクエリにヒントを与えることができます。

  1. このクエリだけを再コンパイルします
  2. すべての変数の値を解決します(sprocが呼び出された後にそれらがわかります)
  3. 解決されたすべての変数を定数に置き換え、定数述語部分を削除します

例:p_customerId = 1000を渡すと、「1000 is null」の式は常にfalseになるため、オプティマイザーはそれを無視します。これによりCPUのオーバーヘッドがいくらか追加されますが、ほとんどの場合、大規模なレポートプロシージャと呼ばれることはめったにないため、ここでは問題ありません。

Oracleでそれを行う方法はありますか?Dynamic-SQLはオプションではありません。

追加します

「p_customerIdisnull」と「p_eventTypeIdisnull」がない同じプロシージャは、約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

1つの列インデックスは、インデックス定義に格納されていないため、役に立ちません。(顧客ID、イベントID、ID)にインデックスを作成することは許可されていますか?このようにして、必要なすべての列がインデックスに登録されます。

于 2012-12-26T18:14:04.507 に答える