[Résolu][MYSQL] lister les doublons + rapidement

lister les doublons + rapidement [Résolu][MYSQL] - SQL/NoSQL - Programmation

Marsh Posté le 06-08-2007 à 12:22:12    

Bonjour,
 
J'ai un programme en Php pour gérer des contacts dans une base de données MySql.
L'une des fonctionnalités est de pouvoir lister les contacts qui ont le même email, pour éventuellement supprimer ou modifier ces contacts.
 
Dans la table contacts, j'ai un champ email, et je peux trouver les contacts en doublon sur l'email avec cette requete:
 

Code :
  1. SELECT * FROM contacts GROUP BY email HAVING COUNT(email) > 1


 
Mais cette requête ne me donne qu'un contact par email. Et j'ai besoin de récupérer tous les contacts qui ont un email qu'on retrouve ailleur dans la table.
 
J'utilise alors cette requête:
 

Code :
  1. SELECT * FROM contacts WHERE email IN ( SELECT email FROM contacts GROUP BY email HAVING COUNT(email) > 1 )


 
Là, ça marche.
Le problème, maintenant, c'est que dès que la table de contacts commence à devenir un peu grande (1000, 2000 contacts....), la requete est très longue à s'executer.
 
J'ai déjà remarqué ça, avec MySql, quand j'utilise un WHERE avec un IN suivi d'une requête interne....
Et je me demandais, donc, si y'avait moyen de faire sans passer par une reqête interne.
 
J'ai vu dans un autre thread que mysql proposait une fonction group_concat, qui pourrait marcher ici, mais ça m'embète un peu: pas sûr de retrouver ça si on change de SGBD...
 
Voilà, voilà... si quelqu'un a une idée ?
 
Merci d'avance pour votre aide.
Nicolas


Message édité par dj3c1t le 09-09-2007 à 19:29:55
Reply

Marsh Posté le 06-08-2007 à 12:22:12   

Reply

Marsh Posté le 06-08-2007 à 13:07:53    

Je crois que si la requête met du temps, c'est parce qu'il refait la sous-requête à chaque fois (donc un traitement en N²)
Tu peux prendre les résultats de ta première requête (SELECT email FROM contacts GROUP BY email HAVING COUNT(email) > 1), créer une liste statique avec les valeurs des emails en php/java/... de la forme '("email1@truc.com","email2@...",...)' et t'en servir comme condition pour le IN de la seconde requête (SELECT * FROM contacts WHERE email IN (liste_statique))
 
Je sais pas si c'est idéal mais j'ai déjà eu de bons résultats en utilisant cette méthode


---------------
The Rom's, à votre service
Reply

Marsh Posté le 06-08-2007 à 14:50:20    

Nickel !!!
 
Comme j'étais pas sûr de la taille de ma liste statique, je suis passé par une table temporaire:
 

Code :
  1. CREATE TEMPORARY TABLE tmp_xxx AS SELECT email FROM contacts GROUP BY email HAVING COUNT(email) > 1


 
puis:
 

Code :
  1. SELECT contacts.* FROM contacts, tmp_xxx WHERE contacts.email=tmp_xxx.email


 
avec le nom de ma table temporaire (tmp_xxx) généré avec php pour un nom unique à chaque fois.
 
Et là.... punaise, ça va carrément plus vite qu'avec une sous-requête !
 
Merci beaucoup pour ta réponse, TheRom_s !

Reply

Marsh Posté le 06-08-2007 à 16:06:07    

Quelle bouse infâme MySQL...
 
Il n'est pas du tout censé refaire la sous-requête à chaque fois...
 
Sinon, en plus propre :

Code :
  1. SELECT c1.*
  2. FROM contacts c1
  3. LEFT OUTER JOIN contacts c2 ON c2.id != c1.id AND c2.email = c1.email
  4. WHERE c2.id IS NOT NULL


 
Ca devrait donner le même résultat.


Message édité par MagicBuzz le 06-08-2007 à 17:50:51
Reply

Marsh Posté le 06-08-2007 à 17:01:06    

Héhé, oui, y'a sans doute des SGBD mieux conçus... ma foi.
 
interressante, en tout cas, ta requête.
'suis pas un virtuose du LEFT OUTER JOIN, mais là pour le coup ça m'intrigue...
 
 :jap:


Message édité par dj3c1t le 06-08-2007 à 17:36:28
Reply

Marsh Posté le 06-08-2007 à 17:51:17    

ben en fait (logiquement) ça retourne les lignes où il existe un ID différent pour la même valeur de l'email.
 
c'est à tester, mais ça devrait marcher.

Reply

Marsh Posté le 06-08-2007 à 20:09:28    

oui, ça marche trés bien.
mais sur une table en particulier, j'obtenais pas le même nombre de résultats que quand je faisais une requête intermédiaire (avec une liste statique ou une table temporaire).
 
...
je viens de comprendre: ta requête marche impec pour les doublons au sens strict du terme.
je veux dire: si dans une table de contacts, un email est attribué soit à un contact soit à deux, alors c'est bon, la requête liste les contacts qui ont un email qu'on retrouve une fois ailleur (les doublons, donc).
 
mais si trois contacts ont le même email, on se retrouve avec deux fois le même contact (même identifiant) dans le résultats.
si quatre contacts ont le même email, chacun de ces contacts se retrouve trois fois dans le résultat, etc.
 
Cette requête a cependant l'avantage d'être rapide et de se faire en une seule fois, et on doit pouvoir s'en sortir en faisant un distinct sur l'id... quelque chose comme :
 

Code :
  1. SELECT DISTINCT(c1.id), c1.*
  2. FROM contacts c1 LEFT OUTER JOIN contacts c2
  3. ON c2.id != c1.id AND c2.email = c1.email
  4. WHERE c2.id IS NOT NULL;


 
bon, c'est à paufiner après, parce qu'on se retrouve du coup avec deux colones "id"... donc en précisant par exemple champ par champ se qui doit être récupéré...
 
Merci bien en tout cas pour vos réponses !
Les deux solutions sont vraiment beaucoup plus rapides qu'avec une sous-requête !


Message édité par dj3c1t le 07-08-2007 à 11:51:26
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed