2009-10-28 6 views
2

Quelle est la «meilleure pratique» générale pour ce type de fonctionnalité.Optimisation de la requête Mysql

J'ai un tableau d'utilisateurs un tableau des sondages et un tableau des réponses au sondage sur un site Web. Je veux charger une page qui charge un sondage auquel un utilisateur n'a pas encore répondu.

Quelle est la façon la plus efficace et la meilleure de s'y prendre?

choses que j'ai essayé qui semble lente/pas optimale:

Une requête avec emboîtés en utilisant NOT IN sélectionne

SELECT p.id 
FROM poll p 
WHERE p.id NOT IN (
    SELECT r.pollID 
    FROM responses r 
    WHERE r.username = 'someuser' 
) 

Une requête qui utilise à gauche rejoint

LEFT JOIN responses ON (polls.id = responses.pollID 
AND responses.username = 'someuser') 
WHERE 
responses.username IS NULL 

deux ces solutions semblent très peu évoluer.

Autres suggestions? Ouvert à tout ce qui sort de la boîte. (I.E. solutions qui ne sont pas limitées à seulement différents types de requêtes mysql)

+0

avez-vous des indices appropriés sur vos tables? – longneck

+1

Utilisez la commande EXPLAIN avant votre requête pour voir comment MySQL décompose la requête –

Répondre

3

Ces deux requêtes sont de même efficacité aussi longtemps que vous avez un indice composite sur responses (pollID, username)

Si vos requêtes sont lentes, ce moyen le plus probablement vous n'avez pas cet indice.

LEFT JOIN combiné avec IS NULL sur une colonne non NULL est optimisé par MySQL afin qu'il renvoie une ligne dès qu'il voit qu'il n'y a pas de valeur correspondante dans la colonne de droite. Vous pouvez le voir dans le EXPLAIN sous la forme Not exists dans la colonne Extra.

NOT IN est optimisé de la même manière aussi, vous pouvez le voir comme <not exists> dans le message d'avertissement fourni par le EXPLAIN EXTENDED.

Voir cette entrée dans mon blog pour plus de détails:

-1

Je pense qu'un Left Join va être votre meilleur pari ici. Cependant, je suis confus quant à la raison pour laquelle dans votre exemple vous vérifiez le nom d'utilisateur, puis dans la clause where, voir si c'est null. il devrait ressembler à ceci:

LEFT JOIN responses ON (polls.id = responses.pollID) 
WHERE 
responses.username = 'someuser' 
+0

Cela ne va-t-il pas être un fardeau lorsque les utilisateurs ont répondu à des milliers de sondages? En outre, j'essaie de trouver un sondage auquel l'utilisateur n'a pas encore répondu. Votre solution trouverait-elle des sondages auxquels elle a répondu? – Brian

+0

Parce qu'il veut éviter de récupérer des lignes où le sondage est déjà répondu. À moins que ce soit spécifiquement ce qui cause la lenteur (voir ma réponse) c'est en fait une chose parfaitement bien à faire. – DVK

0

La jointure gauche devrait fonctionner très bien si vous donnez responses une clé composée sur pollID et username.

Bien qu'il soit un peu pénible que vous utilisiez un nom d'utilisateur en tant que clé, par opposition à un ID utilisateur numérique.

+0

Pouvez-vous élaborer sur les conséquences de l'utilisation du nom d'utilisateur comme clé? Désolé, je manque de compréhension à certains de cela. – Brian

+0

Détruit le stockage, rend les opérations qui l'utilisent un peu plus lent, peut-être (si c'est une colonne de largeur variable) rend la table variable-largeur au lieu de la largeur fixe, ce qui rend également les choses plus lentes. Et c'est juste un peu désordonné. – chaos

0

Solution # 1:

Comment un tout droit rejoindre gauche effectuer pour vous?

LEFT JOIN responses ON (polls.id = responses.pollID 
AND responses.username = 'someuser') 

Si elle effectue OK, vous pouvez simplement récupérer une liste complète des sondages comme celui-ci, puis filtrer les lignes où le nom d'utilisateur est non nul dans le code de l'appelant.

Solution # 2:

Assurez-vous que vos indices sont OK. Vous devriez avoir l'index ann dans le nom d'utilisateur (ou l'ID de sondage + le nom d'utilisateur) dans les réponses.