Mysql
 sql >> Base de données >  >> RDS >> Mysql

SQL UNION ALL pour éliminer les doublons

Mais dans l'exemple, la première requête a une condition sur la colonne a , alors que la deuxième requête a une condition sur la colonne b . Cela vient probablement d'une requête difficile à optimiser :

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

Cette requête est difficile à optimiser avec une simple indexation B-tree. Le moteur recherche-t-il un index sur la colonne a ? Ou sur la colonne b ? Dans tous les cas, la recherche de l'autre terme nécessite un balayage de table.

D'où l'astuce d'utiliser UNION pour séparer en deux requêtes pour un terme chacune. Chaque sous-requête peut utiliser le meilleur index pour chaque terme de recherche. Ensuite, combinez les résultats en utilisant UNION.

Mais les deux sous-ensembles peuvent se chevaucher, car certaines lignes où b=Y peut aussi avoir a=X auquel cas ces lignes apparaissent dans les deux sous-ensembles. Par conséquent, vous devez éliminer les doublons, sinon voir certaines lignes deux fois dans le résultat final.

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

UNION DISTINCT coûte cher car les implémentations typiques trient les lignes pour trouver les doublons. Tout comme si vous utilisiez SELECT DISTINCT ... .

Nous avons également l'impression que c'est encore plus de travail "gaspillé" si les deux sous-ensembles de lignes que vous fusionnez ont beaucoup de lignes apparaissant dans les deux sous-ensembles. Cela fait beaucoup de lignes à éliminer.

Mais il n'est pas nécessaire d'éliminer les doublons si vous pouvez garantir que les deux ensembles de lignes sont déjà distincts. Autrement dit, si vous garantissez qu'il n'y a pas de chevauchement. Si vous pouvez compter sur cela, alors il serait toujours impossible d'éliminer les doublons, et donc la requête peut sauter cette étape, et donc sauter le tri coûteux.

Si vous modifiez les requêtes afin qu'elles soient garanties de sélectionner des sous-ensembles de lignes qui ne se chevauchent pas, c'est une victoire.

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

Ces deux ensembles sont garantis sans chevauchement. Si le premier ensemble a des lignes où a=X et le deuxième ensemble a des lignes où a!=X alors il ne peut y avoir aucune ligne dans les deux ensembles.

La deuxième requête n'en attrape donc que quelques des lignes où b=Y , mais toute ligne où a=X AND b=Y est déjà inclus dans le premier ensemble.

Ainsi, la requête aboutit à une recherche optimisée pour deux OR termes, sans produire de doublons, et ne nécessitant pas d'UNION DISTINCT opération.