Terwijl je dit zou kunnen doen...
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
... de prestaties met dynamische SQL zijn meestal beter , omdat het een meer gericht zoekplan zal genereren. In de bovenstaande query kan Oracle niet zeggen of een index op bcode of lb moet worden gebruikt of typ of edate, en zal waarschijnlijk elke keer een volledige tabelscan uitvoeren.
Natuurlijk moet je moeten gebruik bindvariabelen in uw dynamische query, voeg de letterlijke waarden niet samen in de tekenreeks, anders zullen de prestaties (en schaalbaarheid en beveiliging) zeer slecht zijn .
Voor alle duidelijkheid:de dynamische versie die ik in gedachten heb, zou als volgt werken:
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;
Dit betekent dat de resultaatquery zal "sargable" zijn (een nieuw woord voor mij moet ik toegeven!) aangezien de resulterende query-run (bijvoorbeeld):
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
Ik accepteer echter dat dit in dit voorbeeld tot 16 harde parsen kan vereisen. De "and :bv is null"-clausules zijn vereist bij het gebruik van native dynamische SQL, maar kunnen worden vermeden door DBMS_SQL te gebruiken.
Opmerking:het gebruik van (1=1 or :bindvar is null)
wanneer de bindvariabele null is, werd gesuggereerd in een opmerking van Michal Pravda, omdat het de optimizer in staat stelt de clausule te elimineren.