sql >> Databáze >  >> RDS >> Oracle

PL/SQL - Volitelné podmínky v klauzuli where - bez dynamického SQL?

Zatímco byste to mohli udělat...

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

... výkon pomocí dynamického SQL bude obvykle lepší , protože vygeneruje cílenější plán dotazů. Ve výše uvedeném dotazu Oracle nedokáže říct, zda použít index pro bcode nebo lb nebo typ nebo edate, a pravděpodobně pokaždé provede úplné prohledání tabulky.

Samozřejmě, že musíte použijte v dynamickém dotazu proměnné vazby, nezřetězujte doslovné hodnoty do řetězce, jinak bude výkon (a škálovatelnost a zabezpečení) velmi špatný .

Aby bylo jasno, dynamická verze, kterou mám na mysli, by fungovala takto:

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;

To znamená, že dotaz na výsledek bude být "sargable" (pro mě nové slovo musím přiznat!), protože výsledný běh dotazu bude (například):

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

Souhlasím však s tím, že by to v tomto příkladu mohlo vyžadovat až 16 tvrdých analýz. Klauzule "and :bv is null" jsou vyžadovány při použití nativního dynamického SQL, ale lze se jim vyhnout použitím DBMS_SQL.

Poznámka:použití (1=1 or :bindvar is null) když je proměnná bind null navrhl v komentáři Michal Pravda, protože umožňuje optimalizátoru klauzuli eliminovat.



  1. Server ORACLE aktualizuje záznamy s tabulkovým vztahem 1 až mnoho ve spouštěči

  2. Někdo někdy použil PayPal Website Payments Standard s proměnnými SESSION?

  3. Naformátujte číslo jako procento v MySQL

  4. ERROR 2003 (HY000):Nelze se připojit k serveru MySQL na AWS RDS