sql >> Database >  >> RDS >> Mysql

SQL UNION ALL om duplicaten te elimineren

Maar in het voorbeeld heeft de eerste query een voorwaarde in kolom a , terwijl de tweede zoekopdracht een voorwaarde heeft in kolom b . Dit kwam waarschijnlijk van een zoekopdracht die moeilijk te optimaliseren is:

SELECT * FROM mytable WHERE a=X OR b=Y

Deze query is moeilijk te optimaliseren met eenvoudige B-tree-indexering. Zoekt de engine een index op kolom a ? Of op kolom b ? Hoe dan ook, het zoeken op de andere term vereist een tabelscan.

Vandaar de truc om UNION te gebruiken om te scheiden in twee zoekopdrachten voor elk één term. Elke subquery kan de beste index voor elke zoekterm gebruiken. Combineer vervolgens de resultaten met UNION.

Maar de twee subsets kunnen elkaar overlappen, omdat sommige rijen waar b=Y kan ook a=X . hebben in dat geval komen dergelijke rijen in beide subsets voor. Daarom moet je dubbele eliminatie doen, of anders zie je sommige rijen twee keer in het eindresultaat.

SELECT * FROM mytable WHERE a=X 
UNION DISTINCT
SELECT * FROM mytable WHERE b=Y

UNION DISTINCT is duur omdat typische implementaties de rijen sorteren om duplicaten te vinden. Net zoals wanneer je SELECT DISTINCT ... .

We hebben ook het idee dat het nog meer "verspild" werk is als de twee subsets van rijen die u samenvoegt veel rijen hebben die voorkomen in beide subsets. Het zijn veel rijen om te elimineren.

Maar het is niet nodig om duplicaten te elimineren als u kunt garanderen dat de twee sets rijen al verschillend zijn. Tenminste, als je garandeert dat er geen overlap is. Als u daarop kunt vertrouwen, zou het altijd een no-op zijn om duplicaten te elimineren, en daarom kan de query die stap overslaan en dus de kostbare sortering overslaan.

Als u de zoekopdrachten zo wijzigt dat ze gegarandeerd niet-overlappende subsets van rijen selecteren, is dat een overwinning.

SELECT * FROM mytable WHERE a=X 
UNION ALL 
SELECT * FROM mytable WHERE b=Y AND a!=X

Deze twee sets hebben gegarandeerd geen overlap. Als de eerste set rijen heeft waar a=X en de tweede set heeft rijen waar a!=X dan kan er geen rij zijn die in beide sets zit.

De tweede zoekopdracht vangt daarom slechts enkele van de rijen waar b=Y , maar elke rij waar a=X AND b=Y zit al in de eerste set.

De zoekopdracht levert dus een geoptimaliseerde zoekopdracht op voor twee OR voorwaarden, zonder duplicaten te produceren, en waarvoor geen UNION DISTINCT . nodig is bediening.



  1. Hoe krijg ik de huidige tijdzonenaam in Postgres 9.3?

  2. Utf8 gebroken tekens detecteren in MySQL

  3. CONCAT met GROUP_CONCAT in mysql

  4. Entity Framework + MySQL - Waarom zijn de prestaties zo slecht?