sql >> Database >  >> RDS >> Oracle

PL/SQL - Optionele voorwaarden in waar-clausule - zonder dynamische sql?

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.



  1. mysql_connect():Er kon geen verbinding worden gemaakt omdat de doelmachine dit actief weigerde

  2. Meerdere kolommen in mysql bijwerken met nodejs

  3. is er een alternatief voor het gebruik van een for-lus om meerdere query's in te voegen?

  4. UniVerse-tips