Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

PL / SQL - Các điều kiện tùy chọn trong mệnh đề where - không có sql động?

Trong khi bạn có thể làm điều này ...

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

... hiệu suất sử dụng SQL động thường sẽ tốt hơn , vì nó sẽ tạo ra một kế hoạch truy vấn được nhắm mục tiêu hơn. Trong truy vấn trên, Oracle không thể cho biết nên sử dụng chỉ mục trên bcode hay lb hay type hoặc edate, và có thể sẽ thực hiện quét toàn bộ bảng mỗi lần.

Tất nhiên, bạn phải sử dụng các biến liên kết trong truy vấn động của bạn, không nối các giá trị chữ vào chuỗi, nếu không hiệu suất (và khả năng mở rộng và bảo mật) sẽ rất kém .

Nói rõ hơn, phiên bản động mà tôi nghĩ đến sẽ hoạt động như sau:

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;

Điều này có nghĩa là truy vấn kết quả sẽ là "sargable" (một từ mới đối với tôi, tôi phải thừa nhận!) vì kết quả chạy truy vấn sẽ là (ví dụ):

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

Tuy nhiên, tôi chấp nhận rằng điều này có thể yêu cầu tối đa 16 phân đoạn cứng trong ví dụ này. Các mệnh đề "và:bv là null" được yêu cầu khi sử dụng SQL động gốc, nhưng có thể tránh được bằng cách sử dụng DBMS_SQL.

Lưu ý:việc sử dụng (1=1 or :bindvar is null) khi biến liên kết là null được đề xuất trong một nhận xét của Michal Pravda, vì nó cho phép trình tối ưu hóa loại bỏ mệnh đề.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Chuyển đổi ngày giờ cục bộ (với múi giờ) thành dấu thời gian Unix trong Oracle

  2. Cách đăng ký Cơ sở dữ liệu có thể cài đặt (PDB) với LISTENER mới được tạo

  3. SQL tiêu chuẩn thay thế cho Oracle DECODE

  4. Làm cách nào để phân tích cú pháp chuỗi JSON trong PL / SQL

  5. JPA - EclipseLink - Cách thay đổi lược đồ mặc định