あなたはこれを行うことができますが...
select num
from (select distinct q.num
from cqqv q
where 1=1
and (:bcode is null or q.bcode = :bcode)
and (:lb is null or q.lb = :lb)
and (:type is null or q.type = :type)
and (:edate is null or q.edate > :edate - 30)
order by dbms_random.value()) subq
where rownum <= :numrows
...動的SQLを使用したパフォーマンスは通常優れています 、よりターゲットを絞ったクエリプランが生成されるためです。上記のクエリでは、Oracleはbcodeまたはlbにインデックスを使用するか、typeまたはedateを使用するかを判断できず、おそらく毎回全表スキャンを実行します。
もちろん、あなたはしなければならない リテラル値を文字列に連結せずに、動的クエリでバインド変数を使用します。そうしないと、パフォーマンス(およびスケーラビリティとセキュリティ)が非常に悪いになります。 。
明確にするために、私が考えている動的バージョンは次のように機能します:
declare
rc sys_refcursor;
q long;
begin
q := 'select num
from (select distinct q.num
from cqqv q
where 1=1';
if p_bcode is not null then
q := q || 'and q.bcode = :bcode';
else
q := q || 'and (1=1 or :bcode is null)';
end if;
if p_lb is not null then
q := q || 'and q.lb = :lb';
else
q := q || 'and (1=1 or :lb is null)';
end if;
if p_type is not null then
q := q || 'and q.type = :type';
else
q := q || 'and (1=1 or :type is null)';
end if;
if p_edate is not null then
q := q || 'and q.edate = :edate';
else
q := q || 'and (1=1 or :edate is null)';
end if;
q := q || ' order by dbms_random.value()) subq
where rownum <= :numrows';
open rc for q using p_bcode, p_lb, p_type, p_edate, p_numrows;
return rc;
end;
これは、結果クエリがになることを意味します 結果として実行されるクエリは(たとえば)次のようになるため、「sargable」(私が認めなければならない新しい単語です!)になります。
select num
from (select distinct q.num
from cqqv q
where 1=1
and q.bcode = :bcode
and q.lb = :lb
and (1=1 or :type is null)
and (1=1 or :edate is null)
order by dbms_random.value()) subq
where rownum <= :numrows
ただし、この例では、これには最大16のハード解析が必要になる可能性があることを認めます。ネイティブ動的SQLを使用する場合は、「and:bv is null」句が必要ですが、DBMS_SQLを使用することで回避できます。
注:(1=1 or :bindvar is null)
の使用 バインド変数がnullの場合、オプティマイザーが句を削除できるため、MichalPravdaのコメントで提案されました。