2009-10-24 5 views
0

Je viens permis au log lent (+ ne pas utiliser les index) et que je reçois des centaines d'entrées pour le même genre de requête (seulement user changements)MySQL n'utilisant des index

SELECT id 
    , name 
    FROM `all` 
WHERE id NOT IN(SELECT id 
        FROM `picks` 
        WHERE user=999) 
ORDER BY name ASC; 

EXPLAIN donne:

+----+--------------------+-------------------+-------+------------------+--------+---------+------------+------+------------------------------------------+ 
| id | select_type  | table    | type | possible_keys | key | key_len | ref  | rows | Extra         | 
+----+--------------------+-------------------+-------+------------------+--------+---------+------------+------+------------------------------------------+ 
| 1 | PRIMARY   | all    | index | NULL    | name | 156  | NULL  | 209 | Using where; Using index; Using filesort | 
| 2 | DEPENDENT SUBQUERY | picks    | ref | user,user_2,pick | user_2 | 8  | const,func | 1 | Using where; Using index     | 
+----+--------------------+-------------------+-------+------------------+--------+---------+------------+------+------------------------------------------+ 

Une idée sur la façon d'optimiser cette requête? J'ai essayé avec un tas d'index différents sur des champs différents mais rien.

Répondre

0

Je ne suis pas nécessairement d'accord que «pas dans» et «existe» sont TOUJOURS mauvais choix de performance, cependant, il pourrait être dans cette situation.

Vous pourriez être en mesure d'obtenir vos résultats en utilisant une requête beaucoup plus simple:

SELECT id 
    , name 
    FROM `all` 
    , 'picks' 
WHERE all.id = picks.id 
    AND picks.user <> 999 
ORDER BY name ASC; 
+0

Cela obtiendra tous les choix appartenant à un utilisateur, sauf le 999, non? Ce que la requête fait (mais pas d'une manière efficace) obtient la liste des choix 'disponibles' mais enlève ceux déjà choisis par l'utilisateur. –

+0

Cette requête ne retournerait rien pour les lignes qui n'ont pas d'entrée correspondante dans 'picks', alors que la requête d'origine le ferait. –

+0

assez simple corriger, juste externe rejoindre. – northpole

0

"pas dans" et "existe" toujours mauvais choix pour la performance. Peut être laissé se joindre à chiquer "NULL" sera mieux l'essayer.

0

C'est probablement la meilleure façon d'écrire la requête. Sélectionnez tout de all et essayer de trouver des lignes correspondantes de picks qui partagent la même id et user est 999. Si une telle ligne n'existe pas, picks.id sera NULL, car elle utilise une jointure externe gauche. Vous pouvez ensuite filtrer les résultats pour renvoyer uniquement ces lignes.

SELECT all.id, all.name 
FROM 
    all 
    LEFT JOIN picks ON picks.id=all.id AND picks.user=999 
WHERE picks.id IS NULL 
ORDER BY all.name ASC