oracle – PL / SQL – where子句中的可选条件 – 没有动态sql?

我有一个查询,不是所有的条件都是必要的.以下是使用所有条件时的示例:
select num
from (select distinct q.num
       from cqqv q
       where q.bcode = '1234567' --this is variable
             and q.lb = 'AXCT' --this is variable
             and q.type = 'privt' --this is variable
             and q.edate > sysdate - 30 --this is variable
       order by dbms_random.value()) subq
where rownum <= 10; --this is variable

标记为–this的部分是可变的部分,很好,变化!如果未指定条件,则不存在认值.例如,如果输入为q.type指定了“*”(但是其他所有内容都相同),则该查询应该匹配所有类型的类型,并执行为:

select num
from (select distinct q.num
       from cqqv q
       where q.bcode = '1234567' --this is variable
             and q.lb = 'AXCT' --this is variable
             --and q.type = 'privt' --this condition ignored because of "type=*" in input
             and q.edate > sysdate - 30 --this is variable
       order by dbms_random.value()) subq
where rownum <= 10; --this is variable

我知道有可能使用动态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个硬解析.使用本机动态sql时,“和:bv为空”子句是必需的,但可以通过使用DBMS_sql来避免.

注意:由Michal Pravda在注释中建议使用(1 = 1或:bindvar为null),因为它允许优化器消除该子句.

相关文章

Java Oracle 结果集是Java语言中处理数据库查询结果的一种方...
Java AES和Oracle AES是现代加密技术中最常使用的两种AES加密...
Java是一种广泛应用的编程语言,具备可靠性、安全性、跨平台...
随着移动互联网的发展,抽奖活动成为了营销活动中不可或缺的...
Java和Oracle都是在计算机领域应用非常广泛的技术,他们经常...
Java 是一门非常流行的编程语言,它可以运行于各种操作系统上...