sql >> Database >  >> RDS >> Oracle

Een blik op de Oracle Group-by Bug

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


  1. PostgreSQL - GROUP BY-clausule of worden gebruikt in een aggregatiefunctie

  2. JDBC - Oracle ArrayIndexOutOfBoundsException

  3. Een aangepaste sortering implementeren

  4. SSL voor PostgreSQL-verbindingsknooppunten