Mysql
 sql >> Database >  >> RDS >> Mysql

SQL UNION ALL per eliminare i duplicati

Ma nell'esempio, la prima query ha una condizione sulla colonna a , mentre la seconda query ha una condizione sulla colonna b . Probabilmente deriva da una query difficile da ottimizzare:

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

Questa query è difficile da ottimizzare con la semplice indicizzazione B-tree. Il motore cerca un indice nella colonna a ? Oppure nella colonna b ? In ogni caso, la ricerca dell'altro termine richiede una scansione della tabella.

Da qui il trucco di usare UNION per separare in due query per un termine ciascuna. Ciascuna sottoquery può utilizzare l'indice migliore per ciascun termine di ricerca. Quindi combina i risultati usando UNION.

Ma i due sottoinsiemi potrebbero sovrapporsi, perché alcune righe dove b=Y può anche avere a=X nel qual caso tali righe si verificano in entrambi i sottoinsiemi. Quindi devi eseguire l'eliminazione dei duplicati, oppure vedere alcune righe due volte nel risultato finale.

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

UNION DISTINCT è costoso perché le implementazioni tipiche ordinano le righe per trovare i duplicati. Proprio come se usi SELECT DISTINCT ... .

Abbiamo anche la percezione che sia un lavoro ancora più "sprecato" se i due sottoinsiemi di righe che stai unendo hanno molte righe che si verificano in entrambi i sottoinsiemi. Ci sono molte righe da eliminare.

Ma non è necessario eliminare i duplicati se si può garantire che i due insiemi di righe siano già distinti. Cioè, se garantisci che non ci sono sovrapposizioni. Se puoi fare affidamento su questo, allora sarebbe sempre impossibile eliminare i duplicati e quindi la query può saltare quel passaggio e quindi saltare il costoso ordinamento.

Se modifichi le query in modo che sia garantito che selezionino sottoinsiemi di righe non sovrapposti, è una vittoria.

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

Questi due set sono garantiti per non avere sovrapposizioni. Se il primo set ha righe in cui a=X e il secondo set ha righe dove a!=X quindi non può esserci riga in entrambi gli insiemi.

La seconda query quindi cattura solo alcuni delle righe dove b=Y , ma qualsiasi riga in cui a=X AND b=Y è già incluso nel primo set.

Quindi la query ottiene una ricerca ottimizzata per due OR termini, senza produrre duplicati e senza richiedere UNION DISTINCT operazione.