2008-12-04 8 views
0

J'ai besoin de conseils concernant les performances de sous-sélection dans MySQL. Pour une raison que je ne peux pas changer, je ne suis pas capable d'utiliser JOIN pour créer un filtre de quesry, je peux seulement ajouter une autre clause AND dans WHERE.MySQL sous-sélectionne la question de performance?

Quelle est la peformance de:

select tasks.* 
from tasks 
where 
    some criteria 
    and task.project_id not in (select id from project where project.is_template = 1); 

par rapport à:

select tasks.* 
from tasks, project 
where 
    some criteria 
    and task.project_id = project.id and project.is_template <> 1; 

Notez qu'il existe nombre relativement restreint de projets whete is_template = 1, et il pourrait y avoir un grand nombre de projets dans lesquels is_template <> 1.

Existe-t-il un autre moyen d'obtenir le même résultat sans sous-sélectionner si je ne peux rien changer d'autre et filtrer?

Répondre

5

Je crois que le second est plus efficace car il ne nécessite qu'un seul choix, mais pour être sûr, vous devez EXPLAIN chaque requête et vérifier les résultats.

EXPLAIN select tasks.* 
from tasks 
where 
    some criteria 
    and task.project_id not in (select id from project where project.is_template = 1); 

EXPLAIN select tasks.* 
from tasks, project 
where 
    some criteria 
    and task.project_id = project.id and project.is_template <> 1; 
+0

Nous vous remercions du conseil EXPLAIN. On dirait que l'ajout d'index sur project.is_template aide beaucoup. – Marko

1

Quelle différence il y a entre les deux pourrait dépendre en grande partie de ce que « certains critères » est et quelles sont les possibilités d'utiliser les indices qu'il fournit. Mais notez qu'ils ne sont pas équivalents en termes de résultats s'il y a des tâches qui n'ont pas de projets. Le second est équivalent à ceci:

select tasks.* 
from tasks 
where 
    some criteria 
    and task.project_id in (select id from project where project.is_template <> 1); 
+0

"certains critères" peuvent pratiquement réduire le nombre total d'enregistrements renvoyés. task.project_id est requis, donc ces 2 requêtes sont équivalentes. Je choisis "pas dans" la requête parce que la sous-sélection renvoie beaucoup plus petit nombre d'enregistrements alors il le ferait si je choisis "dans". – Marko

0

Je pense que la première peut évoluer mieux:

Lorsque vous une jointure, interne mysql fait une sorte de table temporaire composée des deux tables jointes selon la jointure conditions spécifiées. Vous n'indiquez pas de condition de jointure, cela crée une table temporaire avec toutes les tâches répertoriées pour tous les projets. Je suis assez sûr (mais vérifiez avec l'outil d'explication) qu'il le fait avant d'appliquer des clauses where. Résultat: s'il y en a 10 de chaque, il aura 10 * 10 lignes = 100. Vous pouvez voir comment cela devient grand au fur et à mesure que les nombres augmentent. Il applique ensuite l'où à cette table temporaire. Par contre, la sous-requête ne sélectionne que les lignes pertinentes de chaque table. Par contre, la sous-requête sélectionne uniquement les lignes pertinentes de chaque table. Mais à moins que la mise à l'échelle ne soit un problème, je ne pense pas que cela ait vraiment d'importance.

+0

personne n'est d'accord avec moi .... je veux une discussion. – benlumley

+0

Essayez une explication simple pour prouver votre erreur. – ysth

0

Évitez les sous-requêtes comme la peste dans les versions MySQL < 6.0, et je doute que vous utilisiez 6.0 étant donné qu'il est encore dans la phase alpha du développement. AFAIK, l'optimiseur de MySQL ne gère pas bien les sous-requêtes. Un travail important a été fait pour réorganiser l'optimiseur pour 6.0 et les sous-requêtes fonctionnent beaucoup mieux maintenant, mais ces changements ne se sont pas répercutés dans les séries 5.0 ou 5.1.

+0

Vous êtes goudronné avec un large pinceau là-bas. Pouvez-vous faire votre commentaire spécifique à cette affaire?Il est difficile de voir comment le manque d'optimisation pourrait causer une différence substantielle à moins qu'il n'exécute la sous-requête de manière répétée pour chaque rangée de tâche, et les tests de performance devraient déterminer si c'est le cas. – ysth

+0

Dans tous les cas que j'ai vus, même lorsque la requête renvoie un ensemble immuable de lignes pour l'opération IN, la sous-requête est exécutée pour chaque résultat de la requête principale. –