Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

PL/SQL - Kondisi opsional di mana-klausa - tanpa sql dinamis?

Meskipun Anda bisa melakukan ini...

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

... kinerja menggunakan SQL dinamis biasanya lebih baik , karena akan menghasilkan rencana kueri yang lebih bertarget. Dalam kueri di atas, Oracle tidak dapat menentukan apakah akan menggunakan indeks pada bcode atau lb atau ketik atau edate, dan mungkin akan melakukan pemindaian tabel penuh setiap saat.

Tentu saja, Anda harus gunakan variabel bind dalam kueri dinamis Anda, jangan gabungkan nilai literal ke dalam string, jika tidak, kinerja (dan skalabilitas, dan keamanan) akan sangat buruk .

Untuk lebih jelasnya, versi dinamis yang saya pikirkan akan bekerja seperti ini:

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;

Ini berarti bahwa kueri hasil akan menjadi "sargable" (sebuah kata baru bagi saya harus saya akui!) karena query yang dihasilkan adalah (misalnya):

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

Namun, saya menerima bahwa ini dapat memerlukan hingga 16 hard parsing dalam contoh ini. Klausa "and :bv is null" diperlukan saat menggunakan SQL dinamis asli, tetapi dapat dihindari dengan menggunakan DBMS_SQL.

Catatan:penggunaan (1=1 or :bindvar is null) ketika variabel bind adalah null disarankan dalam komentar oleh Michal Pravda, karena memungkinkan pengoptimal untuk menghilangkan klausa.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. simpan karakter khusus ansi di database oracle menggunakan php

  2. Pengguna Umum Dengan hak istimewa SYSBACKUP

  3. ORA-01704:string literal terlalu panjang 'Kesalahan saat memasukkan dokumen XML dalam tipe kolom Oracle XMLTYPE'

  4. Buat Urutan dengan MULAI DENGAN dari Query

  5. Oracle SQL:Cara menggunakan lebih dari 1000 item di dalam klausa IN