sql >> Database teknologi >  >> RDS >> Oracle

Et kig på Oracle Group-by Bug

Oracle introducerede en ny funktion, gruppe for eliminering, til forespørgsler, hvor gruppe for kolonne også er tabellens unikke nøgle. Som med mange nye funktioner har denne stadig ikke fået løst alle knæk. Problemet opstår, når nøgleværdier manipuleres med funktionskald. Følgende eksempel vil illustrere problemet ved at bruge en tabel med en DATE som den primære nøgle og ved at udtrække året udtrækkes med TO_CHAR eller EXTRACT.

En tabel oprettes som følger:

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;

Når forespørgslen vist nedenfor udføres, giver den følgende resultater:

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 'ved' ikke, at nøgleværdierne er blevet manipuleret, så de ikke længere er unikke, derfor anvender optimeringsværktøjet den unikke-nøgle-baserede gruppe-ved-eliminering med mindre end fantastiske resultater,

EXTRACT er ikke bedre og giver de samme resultater. Denne adfærd styres af parameteren "_optimizer_aggr_groupby_elim", som er sat til sand som standard. Da det er en skjult parameter, rapporteres dens indstilling ikke af Oracle i nogen af ​​V$PARAMEter- eller V$SPPARAMETER-visningerne. Løsningen er blot at sætte denne parameter til falsk. Men at have den aktiv kan hjælpe andre gruppe-for-forespørgsler, hvor de unikke nøgleværdier ikke manipuleres.

Indtast Oracle 19c, hvor denne funktionalitet er delvist rettet:

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


Desværre er EXTRACT stadig ødelagt i 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

Givet virkelig unikke nøgleværdier ville en gruppe-for-forespørgsel naturligvis producere en optælling på 1 for hver nøgle. Og lige så indlysende burde Oracle være i stand til at genkende, hvornår værdier ikke længere er unikke og påberåbe sig den rette gruppe-for-mekanisme. Det er tilbage at se, om versioner efter 19c vil rette den anden betingelse og dermed returnere korrekte resultater uden at skulle slå denne funktion fra.

Dette påvirker muligvis ikke enhver installation af Oracle nyere end 12.1, men det er værd at vide, hvis forkerte resultater begynder at blive vist i udvalgte grupper efter forespørgsler.

# # #

Se artikler afDavid Fitzjarrell


  1. SQL Pivot - Ved, hvordan man konverterer rækker til kolonner

  2. Den mest elegante måde at generere permutationer i SQL server

  3. Sådan automatiseres dataindsamling på SQL Server-databasevækst

  4. Sådan aktiverer du understøttelse af fremmed nøgle i SQLite