Oracle
 sql >> база данни >  >> RDS >> Oracle

PL/SQL - Незадължителни условия в клаузата where - без динамичен sql?

Докато можете да направите това...

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 твърди анализа в този пример. Клаузите "and :bv is null" са задължителни при използване на естествен динамичен SQL, но могат да бъдат избегнати чрез използване на DBMS_SQL.

Забележка:използването на (1=1 or :bindvar is null) когато променливата за свързване е нула, беше предложено в коментар от Михал Правда, тъй като позволява на оптимизатора да елиминира клаузата.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Автоматично увеличение за Oracle

  2. ORA-01873:водеща прецизност

  3. Вложена функция PIPELINED

  4. Как да деактивирате PL/SQL в Oracle заявки

  5. Как да видите съдържанието на Check Constraint на Oracle