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の記事を見る