Comment optimiser une requête pourtant simple ? [c'était moi] [MySQL] - SQL/NoSQL - Programmation
Marsh Posté le 09-04-2004 à 18:08:25
Euh... T'es au courant qu'aucune des trois requètes que tu montres ne donne les mêmes résultats?
Marsh Posté le 09-04-2004 à 18:45:50
La raison de ces comparaisons, c'est de chercher la meilleure optimisation interne de MySQL, si tu n'as pas compris...
Et si tu comprends si bien ces fonctionnements, tu vas me dire pourquoi MySQL scanne l'intégralité des deux index pour la première requête ?
edit : c'est vrai que j'ai l'air agressif , sorry !
Marsh Posté le 09-04-2004 à 19:01:21
kalex a écrit : |
tu trouves pas que tu es un poil agressif?
Marsh Posté le 09-04-2004 à 19:03:49
gizmo a écrit : produit cartésien. |
Je vois...
Alors comment faire ? En fait, je veux juste savoir s'il y a un ID de 7, soit dans TABLE1 soit dans TABLE2.
Marsh Posté le 09-04-2004 à 19:06:41
uriel a écrit : |
Oui, mais les réponses trop laconiques ont le dont de m'énerver...
Quand on a la solution pourquoi ne pas la donner ?
Enfin, désolé.
Marsh Posté le 09-04-2004 à 19:08:36
Et tu te fouts de connaitre les autres champs? tu veux juste savoir s'il existe? Dans ce cas, réponse 2.
Marsh Posté le 09-04-2004 à 19:14:42
Réponce 2 ?
Merci de tes efforts, mais que veux-tu dire ? (j'aimerais en être sûr plutôt )
J'aimerais faire ça en une seule requête, parce qu?en deux, je sais faire...
Marsh Posté le 09-04-2004 à 19:21:14
je veux simplement dire que faire cela en une seule requète sans faire de jointure, et donc sans exploser ton temps de calcul, c'est simplement impossible.
Marsh Posté le 09-04-2004 à 19:29:01
Merci.
Je vais encore t'emmerder avec une dernière question.
Si je fait :
SELECT * FROM TABLE1 T1, TABLE2 T2 WHERE T1.ID = 7 OR T2.ID = 7 LIMIT 1
L'index est-il réellement passé en revue ? A priori non, puisqu'on s'arrête au premier résultat ? Le temps de calcul devrait rester très bon ?
Marsh Posté le 09-04-2004 à 20:28:08
Non, le problème n'est pas là.
Quand tu fais une telle requète, voici ce qui se passe en interne:
- l'interpréteur voit qu'il y a deux tables, il va donc chercher à les joindre
- l'interpréteur cherche un critère de jointure, ici il n'y en a pas. Les n colonnes de T1 vont donc recevoir chacune m colonnes de T2, soit n*m.
- Dans cette nouvelle maxi-table, l'interpréteur cherche, ligne par ligne (ou en utilisant l'index s'il y en a un) à vérifier la clause where (or compris)
- l'interpréteur voit une ligne qui correspond à la demande et rempli un objet avec cette ligne
- l'interpréteur voit qu'on lui demande de s'arreter après un objet trouvé, il retourne cet objet.
Tu comprends?
Marsh Posté le 09-04-2004 à 20:30:17
kalex a écrit : Merci. |
Tant qu'on y est :
SELECT 1 FROM TABLE1 T1, TABLE2 T2 WHERE T1.ID = 7 OR T2.ID = 7 LIMIT 1
Ca ne change pas fondamentalement la complexité de la requête, mais il devrait ne s'occuper que des index, et pas du tout du reste de la table
Mais je pense que la solution en 2 requêtes est la meilleure
Marsh Posté le 09-04-2004 à 20:34:30
gizmo a écrit : Non, le problème n'est pas là. |
Je comprends bien, c'est très clair, merci.
Juste un truc, pourquoi explain n'indique pas "Using temporary" lorsqu'il utilise ce mécanisme ?
Marsh Posté le 09-04-2004 à 20:36:20
mrbebert a écrit : Tant qu'on y est : |
Ca, j'avais déjà compris !
Marsh Posté le 09-04-2004 à 20:38:43
kalex a écrit : Je comprends bien, c'est très clair, merci. |
le résultat de explain dépend d'un SGDB à l'autre. En général, ils indique qqch comme "merge" avec la condition de jointure, mais il faut encore qu'il y en aie une.
Marsh Posté le 09-04-2004 à 20:56:58
Encore merci.
Cependant, je me demande toujours pourquoi UNION avec LIMIT 1 exécute la seconde requête si la première revoit une ligne.
Marsh Posté le 09-04-2004 à 21:07:28
Parce que limit est la dernière des choses qui soit évalué.
Marsh Posté le 09-04-2004 à 21:18:55
J'ai surement l'air d'un boulay.
Mais la base est "consciente" de la clause LIMIT #, puisqu'elle ne calcule et ne retourne que le nombre de ligne # ? Ce comportement est-il différent avec UNION ?
Marsh Posté le 09-04-2004 à 21:57:32
Ce n'est pas évident que la base en tienne compte au moment où elle détermine comment elle va traiter la requête (ce qu'indique l'explain).
Peut être que le LIMIT n'intervient qu'après le début des traitements, lorsque le bon nombre de résultats à été trouvé
Marsh Posté le 09-04-2004 à 22:10:11
Code :
|
S'il y a une ligne de résultat pour T1, @a contiendra le NOM de cette ligne. Il n'y a donc qu'une ligne retournée, mais @b contient à chaque fois le NOM du premier résultat pour T2...
Comme tu dis
Marsh Posté le 09-04-2004 à 23:35:08
C'est peut-être un manque d'optimisation (une sorte de bug en fait !) de MySQL ?
Attendons gizmo qui a l'air calé.
Marsh Posté le 10-04-2004 à 00:13:34
quand je dis que limit est la dernière chose évaluée, dans ce cas, cela dépend si le SGDB est intelligent ou non.
Cas bête:
- il fait la première requète et stocke le tout dans une table temporaire
- il fait la seconde requète et retourne donc un seul résultat (limit ne porte que sur celle-là) dans une seconde table temporaire
- union est appliqué entre les deux tables temporaires pour virer les doublons
Cas intelligent:
- la première requète est exécuté, le résultat blabla...
- l'interpréteur remarque union et donc décide de rajouter les résultats non-doublon de la seconde requète directement dans la table temporaire
-la seonde requète s'arrête après avoire trouvé un résultat
Marsh Posté le 10-04-2004 à 00:42:40
Il ne s'agit, a priori, pas du cas bête puisque @a contient uniquement le nom de la première ligne (la seule retournée). S'il s'agissait du second cas UNION ALL devrait permettre de ne pas traiter les doublons ? Or le résultat est le même avec.
Pour moi le mécanisme logique serait :
- La base remarque LIMIT 1 et UNION ALL, elle sait donc que le 1er résultat trouvé sera suffisant,
- Elle exécute la premiere requête et reçoit un premier résultat,
- Elle s'arrête là.
A la rigueur, elle pourrait remarquer UNION ALL qu'après la réception du premier résultat...
Marsh Posté le 10-04-2004 à 00:53:34
kalex a écrit : Il ne s'agit, a priori, pas du cas bête puisque @a contient uniquement le nom de la première ligne (la seule retournée). |
Marsh Posté le 10-04-2004 à 01:13:05
Citation : cela ne veut rien dire. Dans les deux cas, limit ne touche absolument pas la première requète. La seule info que tu as, c'est qu'il n'y a effectivement qu'une seule ligne qui a un id=7 dans T1 |
Justement non, s'il y en a plusieurs ça change rien (c'est plus des IDs bien sur) !
Changeons :
Code :
|
Ca ne retourne qu'une seule ligne (la 1ere de T1). Et les variables sont assignées comme précédemment.
Marsh Posté le 10-04-2004 à 01:17:30
Dans ce cas, je ne vois qu'une solution: MySQL est encore une fois en dehors de la norme standard SQL. Il faut se plonger dans leur doc pour voir comment ils gèrent les union.
Marsh Posté le 10-04-2004 à 01:20:45
Si je trouve une soluce, je la donnerais ici.
Je te remercie vraiment beaucoup pour ta disponibilité gizmo.
Marsh Posté le 09-04-2004 à 16:54:59
Salut,
Ma requête ressemble à ça :
Elle me renvoie ce que je veux, mais en faisant explain je me rends compte que le type de la requête sur les deux tables est "index" (donc les deux index sont parcourus entièrement !).
Si je divise la requête, la type devient bien sur const (beaucoup mieux) :
J'ai essayé de faire une union, mais après vérification, il y a problème avec la clause LIMIT. Par exemple :
Ceci ne renvoie qu'un seul résultat, mais exécute la requête sur TABLE2 même si TABLE1 a déjà renvoyé un résultat.
Bof, Bof...
Je ne comprends vraiment pas ces comportements.
QQ1 peut m'aider à comprendre ou à optimiser ?
Message édité par kalex le 10-04-2004 à 02:04:35