次のサンプルコードで、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)」を使用してクエリにヒントを与えることができます。
- このクエリだけを再コンパイルします
- すべての変数の値を解決します(sprocが呼び出された後にそれらがわかります)
- 解決されたすべての変数を定数に置き換え、定数述語部分を削除します
例:p_customerId = 1000を渡すと、「1000 is null」の式は常にfalseになるため、オプティマイザーはそれを無視します。これによりCPUのオーバーヘッドがいくらか追加されますが、ほとんどの場合、大規模なレポートプロシージャと呼ばれることはめったにないため、ここでは問題ありません。
Oracleでそれを行う方法はありますか?Dynamic-SQLはオプションではありません。
追加します
「p_customerIdisnull」と「p_eventTypeIdisnull」がない同じプロシージャは、約0.041秒間実行されますが、上のプロシージャは約0.448秒間実行されます(約5.000.000行あります)。