Men i eksemplet har den første forespørgsel en betingelse i kolonne a
, hvorimod den anden forespørgsel har en betingelse i kolonne b
. Dette kom sandsynligvis fra en forespørgsel, der er svær at optimere:
SELECT * FROM mytable WHERE a=X OR b=Y
Denne forespørgsel er svær at optimere med simpel B-træ-indeksering. Søger motoren et indeks på kolonne a
? Eller i kolonne b
? Uanset hvad kræver søgning på det andet udtryk en tabelscanning.
Derfor tricket med at bruge UNION til at adskille i to forespørgsler for en term hver. Hver underforespørgsel kan bruge det bedste indeks for hvert søgeord. Kombiner derefter resultaterne ved hjælp af UNION.
Men de to undersæt kan overlappe hinanden, fordi nogle rækker har b=Y
kan også have a=X
i hvilket tilfælde sådanne rækker forekommer i begge delmængder. Derfor er du nødt til at udføre duplikat-eliminering, ellers kan du se nogle rækker to gange i det endelige resultat.
SELECT * FROM mytable WHERE a=X
UNION DISTINCT
SELECT * FROM mytable WHERE b=Y
UNION DISTINCT
er dyrt, fordi typiske implementeringer sorterer rækkerne for at finde dubletter. Ligesom hvis du bruger SELECT DISTINCT ...
.
Vi har også en opfattelse af, at det er endnu mere "spildt" arbejde, hvis de to delmængder af rækker, du forener, har mange rækker i begge undergrupper. Det er mange rækker, der skal fjernes.
Men der er ingen grund til at eliminere dubletter, hvis du kan garantere, at de to sæt rækker allerede er forskellige. Det vil sige, hvis du garanterer, at der ikke er noget overlap. Hvis du kan stole på det, så ville det altid være en no-op at eliminere dubletter, og derfor kan forespørgslen springe det trin over og derfor springe den dyre sortering over.
Hvis du ændrer forespørgslerne, så de med garanti vælger ikke-overlappende undersæt af rækker, er det en gevinst.
SELECT * FROM mytable WHERE a=X
UNION ALL
SELECT * FROM mytable WHERE b=Y AND a!=X
Disse to sæt har med garanti ingen overlapning. Hvis det første sæt har rækker hvor a=X
og det andet sæt har rækker hvor a!=X
så kan der ikke være nogen række, der er i begge sæt.
Den anden forespørgsel fanger derfor kun nogle af rækkerne hvor b=Y
, men enhver række hvor a=X AND b=Y
er allerede inkluderet i det første sæt.
Så forespørgslen opnår en optimeret søgning efter to OR
vilkår uden at producere dubletter og ikke kræve UNION DISTINCT
operation.