Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2978 connectés 

  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  [MySQL] Comment optimiser une requête pourtant simple ? [c'était moi]

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[MySQL] Comment optimiser une requête pourtant simple ? [c'était moi]

n°696715
kalex
Posté le 09-04-2004 à 16:54:59  profilanswer
 

Salut,
Ma requête ressemble à ça :

Code :
  1. SELECT * FROM TABLE1 T1,  TABLE2 T2 WHERE T1.ID = 7 OR T2.ID = 7


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) :

Code :
  1. SELECT * FROM TABLE1 T1 WHERE T1.ID = 7;
  2. SELECT * FROM TABLE2 T2 WHERE T2.ID = 7;


J'ai essayé de faire une union, mais après vérification, il y a problème avec la clause LIMIT. Par exemple :

Code :
  1. SELECT * FROM TABLE1 T1 WHERE T1.ID = 7
  2. UNION
  3. SELECT * FROM TABLE2 T2 WHERE T2.ID = 7
  4. LIMIT 1


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. :sarcastic:
Bof, Bof...
 
Je ne comprends vraiment pas ces comportements. :heink:
QQ1 peut m'aider à comprendre ou à optimiser ?


Message édité par kalex le 10-04-2004 à 02:04:35
mood
Publicité
Posté le 09-04-2004 à 16:54:59  profilanswer
 

n°696792
gizmo
Posté le 09-04-2004 à 18:08:25  profilanswer
 

Euh... T'es au courant qu'aucune des trois requètes que tu montres ne donne les mêmes résultats?

n°696813
kalex
Posté le 09-04-2004 à 18:33:41  profilanswer
 

T'as essayé de comprendre au moins ?

n°696814
gizmo
Posté le 09-04-2004 à 18:38:49  profilanswer
 

oui, mais toi as-tu seulement compris ce que tu veux...

n°696817
kalex
Posté le 09-04-2004 à 18:45:50  profilanswer
 

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 :o, sorry !


Message édité par kalex le 09-04-2004 à 19:59:39
n°696818
gizmo
Posté le 09-04-2004 à 18:50:59  profilanswer
 

produit cartésien.

n°696824
uriel
blood pt.2
Posté le 09-04-2004 à 19:01:21  profilanswer
 

kalex a écrit :


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 ?


tu trouves pas que tu es un poil agressif?


---------------
IVG en france
n°696825
kalex
Posté le 09-04-2004 à 19:03:49  profilanswer
 

gizmo a écrit :

produit cartésien.

Je vois... :o
Alors comment faire ? En fait, je veux juste savoir s'il y a un ID de 7, soit dans TABLE1 soit dans TABLE2.

n°696827
kalex
Posté le 09-04-2004 à 19:06:41  profilanswer
 

uriel a écrit :


tu trouves pas que tu es un poil agressif?

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é. :o

n°696828
gizmo
Posté le 09-04-2004 à 19:08:36  profilanswer
 

Et tu te fouts de connaitre les autres champs? tu veux juste savoir s'il existe? Dans ce cas, réponse 2.


Message édité par gizmo le 09-04-2004 à 19:09:03
mood
Publicité
Posté le 09-04-2004 à 19:08:36  profilanswer
 

n°696830
kalex
Posté le 09-04-2004 à 19:14:42  profilanswer
 

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...

n°696832
gizmo
Posté le 09-04-2004 à 19:21:14  profilanswer
 

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.

n°696835
kalex
Posté le 09-04-2004 à 19:29:01  profilanswer
 

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 ?

n°696844
gizmo
Posté le 09-04-2004 à 20:28:08  profilanswer
 

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?

n°696845
mrbebert
Posté le 09-04-2004 à 20:30:17  profilanswer
 

kalex a écrit :

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 ?

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 :)


Message édité par mrbebert le 09-04-2004 à 20:32:36
n°696846
kalex
Posté le 09-04-2004 à 20:34:30  profilanswer
 

gizmo a écrit :

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?

Je comprends bien, c'est très clair, merci. :jap:
Juste un truc, pourquoi explain n'indique pas "Using temporary" lorsqu'il utilise ce mécanisme ?

n°696847
kalex
Posté le 09-04-2004 à 20:36:20  profilanswer
 

mrbebert a écrit :

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 :)

Ca, j'avais déjà compris ! ;)

n°696848
gizmo
Posté le 09-04-2004 à 20:38:43  profilanswer
 

kalex a écrit :

Je comprends bien, c'est très clair, merci. :jap:
Juste un truc, pourquoi explain n'indique pas "Using temporary" lorsqu'il utilise ce mécanisme ?


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.

n°696850
kalex
Posté le 09-04-2004 à 20:56:58  profilanswer
 

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.

n°696852
gizmo
Posté le 09-04-2004 à 21:07:28  profilanswer
 

Parce que limit est la dernière des choses qui soit évalué.

n°696853
kalex
Posté le 09-04-2004 à 21:18:55  profilanswer
 

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 ?

n°696855
mrbebert
Posté le 09-04-2004 à 21:57:32  profilanswer
 

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é [:figti]

n°696856
kalex
Posté le 09-04-2004 à 22:10:11  profilanswer
 

Code :
  1. SELECT @a := NOM FROM TABLE1 T1 WHERE T1.ID = 7
  2. UNION
  3. SELECT @b := NOM FROM TABLE2 T2 WHERE T2.ID = 7
  4. LIMIT 1


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 [:figti]

n°696857
mrbebert
Posté le 09-04-2004 à 22:18:49  profilanswer
 

Effectivement, c'est curieux que @b ait une valeur :pt1cable:

n°696889
kalex
Posté le 09-04-2004 à 23:35:08  profilanswer
 

C'est peut-être un manque d'optimisation (une sorte de bug en fait !) de MySQL ?
Attendons gizmo qui a l'air calé. ;)

n°696900
gizmo
Posté le 10-04-2004 à 00:13:34  profilanswer
 

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

n°696908
kalex
Posté le 10-04-2004 à 00:42:40  profilanswer
 

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...


Message édité par kalex le 10-04-2004 à 00:43:44
n°696910
gizmo
Posté le 10-04-2004 à 00:53:34  profilanswer
 

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).
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
 
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.
cela veut juste dire qu'il n'y a pas de ligne avec id=7 dans T2. Autrement, ton modèle est corrompu
 
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...
non, cela ne pourrait être vrai que si tes requètes étaient encapsulées dans des parenthéses, limit en dehors, ce qui n'est pas le cas

n°696911
kalex
Posté le 10-04-2004 à 01:13:05  profilanswer
 

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 :
  1. SELECT @a := NOM FROM TABLE1 T1 WHERE T1.AGE = 7 /* Sans LIMIT, retourne plusieurs lignes. */
  2. UNION
  3. SELECT @b := NOM FROM TABLE2 T2 WHERE T2.AGE = 7 /* Sans LIMIT, retourne plusieurs lignes. */
  4. LIMIT 1

Ca ne retourne qu'une seule ligne (la 1ere de T1). Et les variables sont assignées comme précédemment.


Message édité par kalex le 10-04-2004 à 01:16:39
n°696912
gizmo
Posté le 10-04-2004 à 01:17:30  profilanswer
 

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.

n°696913
kalex
Posté le 10-04-2004 à 01:20:45  profilanswer
 

:cry:Si je trouve une soluce, je la donnerais ici.
 
Je te remercie vraiment beaucoup pour ta disponibilité gizmo. :jap:

mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  [MySQL] Comment optimiser une requête pourtant simple ? [c'était moi]

 

Sujets relatifs
Verifier une table MySQL ... Et les résultats ...Java - Connexion MySQL
[Oracle] Optimisaton requêterequete en PHP/MySQL sur deux base differentes ...
[SQL] [Résolu] Requete avec COUNT et GROUP BYrecherche sur plusieurs tables MySQL
[PHP/MYSQL] Créer table avec des champs issus de variables[C] Un chat simple en C
Requete SQL Oracle : Pourquoi ca ne marche pas ? 
Plus de sujets relatifs à : [MySQL] Comment optimiser une requête pourtant simple ? [c'était moi]


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR