sql >> データベース >  >> RDS >> Oracle

PL / SQL-where-clauseのオプション条件-動的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を使用する場合は、「and:bv is null」句が必要ですが、DBMS_SQLを使用することで回避できます。

    注:(1=1 or :bindvar is null)の使用 バインド変数がnullの場合、オプティマイザーが句を削除できるため、MichalPravdaのコメントで提案されました。



    1. PHPからMySQLに日付を保存するためのベストプラクティス

    2. macOSにSQLiteをインストールする方法

    3. Oracle apex 選択リストと値の非表示

    4. MySQL移動平均計算