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

OracleGroup-byバグの概要

    Oracleは、group by列がテーブルの一意キーでもあるクエリに対して、groupby消去という新機能を導入しました。多くの新機能と同様に、これはまだすべての問題を解決していません。この問題は、キー値が関数呼び出しで操作されるときに発生します。次の例では、主キーとしてDATEを使用するテーブルを使用し、TO_CHARまたはEXTRACTを使用して年を抽出することで問題を説明します。

    次のようにテーブルが作成されます。

    create table bug_test_calendar(
            cal_name   char(17),
            bus_dt   date,
            updt_timestamp       timestamp (6) default systimestamp,
            constraint pk_bug_test_calendar 
                            primary key (bus_dt)
    )
    /
    
    insert into bug_test_calendar (bus_dt)
    select
            sysdate + 10 * rownum
    from 
            all_objects 
    where 
            rownum <= 40 
    /
    
    commit;
    
    

    以下に示すクエリを実行すると、次の結果が生成されます。

    select
            to_char(bus_dt,'YYYY') bus_dt, count(*) ct
    from
           bug_test_calendar
    group by 
            to_char(bus_dt,'YYYY')
    order by 
            to_char(bus_dt,'YYYY')
    /
    
    
    BUS_DF   CT
    -------  --
    2020      1
    2020      1
    ...
    2020      1
    
    40 rows returned
    
    

    Oracleは、キー値が操作されて一意でなくなったことを「認識」していないため、オプティマイザは一意キーベースのgroup-by除去を適用し、結果は優れていません。

    EXTRACTはこれ以上うまくいかず、同じ結果を返します。この動作は、デフォルトでtrueに設定されている「_optimizer_aggr_groupby_elim」パラメーターによって制御されます。これは非表示のパラメータであるため、その設定はOracleによってV$PARAMEterビューまたはV$SPPARAMETERビューのいずれにも報告されません。回避策は、このパラメーターをfalseに設定することです。ただし、これをアクティブにすると、一意のキー値が操作されない他のgroup-byクエリに役立つ場合があります。

    この機能が部分的に修正されているOracle19cに入ります:

    select
            to_char(bus_dt,'YYYY') bus_dt, count(*) ct
    from
           bug_test_calendar
    group by 
            to_char(bus_dt,'YYYY')
    order by 
            to_char(bus_dt,'YYYY')
    /
    
    
    BUS_DF   CT
    -------  --
    2020     40
    
    
    

    残念ながら、EXTRACTは19cでもまだ壊れています:

    select
            to_char(bus_dt,'YYYY') bus_dt, count(*) ct
    from
           bug_test_calendar
    group by 
            extract(year deom bus_dt)
    order by 
            extract(year deom bus_dt)
    /
    
    
    BUS_DF   CT
    -------  ==
    2020      1
    2020      1
    ...
    2020      1
    
    40 rows returned
    

    明らかに、真に一意のキー値が与えられると、group-byクエリはキーごとに1のカウントを生成します。また、当然のことながら、Oracleは、値が一意でなくなったことを認識し、適切なgroup-byメカニズムを呼び出すことができるはずです。 19c以降のバージョンで2番目の条件が修正され、この機能をオフにすることなく正しい結果が返されるかどうかは不明です。

    これは、12.1より新しいOracleのすべてのインストールに影響するわけではありませんが、クエリによって選択したグループに間違った結果が表示され始めた場合は知っておく価値があります。

    ###

    David Fitzjarrellの記事を見る


    1. MySQL CEILING()関数–最も近い整数に切り上げ

    2. SQLServerのシノニムの概要

    3. SQLServer2017でストアドプロシージャを作成する

    4. SQLBulkCopyが存在する場合、挿入または更新する方法はありますか?