Oracle introduceerde een nieuwe functie, group by eliminatie, voor queries waarbij de group by column ook de unieke sleutel van de tabel is. Zoals met veel nieuwe functies heeft deze nog steeds niet alle knikken opgelost. Het probleem ontstaat wanneer sleutelwaarden worden gemanipuleerd met functieaanroepen. Het volgende voorbeeld illustreert het probleem door een tabel te gebruiken met een DATE als primaire sleutel en door het jaar te extraheren wordt het geëxtraheerd met TO_CHAR of EXTRACT.
Een tabel wordt als volgt gemaakt:
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;
Wanneer de onderstaande query wordt uitgevoerd, levert dit de volgende resultaten op:
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 'weet' niet dat de sleutelwaarden zijn gemanipuleerd zodat ze niet langer uniek zijn, dus past de optimizer de op unieke sleutels gebaseerde group-by-eliminatie toe met minder dan geweldige resultaten,
EXTRACT doet het niet beter en levert dezelfde resultaten op. Dit gedrag wordt bepaald door de parameter "_optimizer_aggr_groupby_elim", die standaard is ingesteld op true. Omdat het een verborgen parameter is, wordt de instelling ervan niet gerapporteerd door Oracle in de V$PARAMEter- of V$SPPARAMETER-weergaven. De tijdelijke oplossing is om deze parameter eenvoudig in te stellen op false. Als het echter actief is, kan dit helpen bij andere zoekopdrachten waarbij de unieke sleutel niet wordt gemanipuleerd.
Voer Oracle 19c in, waar deze functionaliteit gedeeltelijk is opgelost:
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
Helaas is EXTRACT nog steeds verbroken in 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
Het is duidelijk dat, gegeven werkelijk unieke sleutelwaarden, een group-by-query een telling van 1 voor elke sleutel zou opleveren. En, net zo voor de hand liggend, Oracle zou in staat moeten zijn om te herkennen wanneer waarden niet langer uniek zijn en het juiste group-by-mechanisme aan te roepen. Het valt nog te bezien of versies na 19c de tweede voorwaarde zullen oplossen en dus correcte resultaten zullen opleveren zonder deze functie uit te hoeven schakelen.
Dit heeft mogelijk geen invloed op elke installatie van Oracle die nieuwer is dan 12.1, maar het is de moeite waard om te weten of er verkeerde resultaten verschijnen in de geselecteerde groep per zoekopdracht.
# # #
Zie artikelen van David Fitzjarrell