Optimisation d'un "not in" [MySQL] - SQL/NoSQL - Programmation
Marsh Posté le 06-01-2006 à 13:12:44
SELECT idmes
FROM forum_messages
WHERE NOT EXISTS ( SELECT *
FROM forum_lu
WHERE forum_lu.ids = forum_messages.ids)
Marsh Posté le 06-01-2006 à 13:20:48
ou
Code :
|
Marsh Posté le 06-01-2006 à 15:12:23
anapajari a écrit : ou
|
C'est plutôt à ce genre de requête que je pensais, étant donné que le not exists ne doit pas être beaucoup moins lourd que le not in.
En tout cas, merci, je vais aller potasser la doc MySQL pour bien comprendre tout ça
Marsh Posté le 06-01-2006 à 15:27:19
Le NOT IN et NOT EXISTS ne fonctionnent généralement pas de la même façon en interne pour un SGBD donné, en général, le NOT EXISTS utilise l'index (s'il existe) sur la clé attaquée dans la table de la sous-requête, tandis que le NOT IN fait (souvent) des table scans.
Marsh Posté le 06-01-2006 à 15:52:23
Le NOT EXISTS fait une oppération similaire à cette requête, du moins sur les SGBD qui ont un optimiseur correct.
Test avec un grand volumes de données :
Recherche du nombre de produits qui n'ont pas fait l'objet d'une commande de vente dans la société 2.
Code :
|
Bon, le test n'est pas méga concluant, puisqu'apparement, avec SQL Server 2000, le NOT IN ne pose pas vraiment de problème de performances
Les plans d'éxécution :
Not Exists :
Left join :
Not In :
On voit bien que le LEFT JOIN et le NOT EXISTS font la même oppération, mais pas au même moment, donc les différences de perfs seront dans tous les cas vraiment minimes.
Par contre, le NOT IN est une véritable usine à gaz, et malgré les très bonnes performances que j'obtiens... Ben moins on joue avec et mieu c'est
A noter que j'ai dans ma base les index suivants (ça explique les bonnes perfs)
Code :
|
Par contre, je n'ai pas de FK entre les deux tables (qui aurait certainement encore amélioré les perfs du LEFT JOIN et du NOT EXISTS) car j'ai des produits commandés qui ne sont pas dans la table des produits (faut pas me demander pourquoi, c'est pas de ma faute )
Marsh Posté le 06-01-2006 à 15:55:12
Au fait, ne me demandez pas pkoi SQL Server utilise "ix_sigfou" sur la table PRO... Parcequ'il ne contient même pas CODPRO et n'est ni unique, ni clustered
Marsh Posté le 06-01-2006 à 15:59:00
Tiens, au fait, un truc important :
Ceux qui sont sous SQL Server du moins, LAISSEZ TOMBER LA SOLUTION DU LEFT JOIN, ELLE EST BIEN PLUS LENTE QUE LE NOT EXISTS !
En effet, si je fais l'explain plan sur tout le lot, j'ai :
LEFT JOIN : 38,97% de coût
NOT EXISTS : 26,96% de coût
NOT IN : 34,07% de coût
DONC : La jointure externe est plus lente que le NOT IN !!!
Pour conclure : le NOT EXISTS c'est bon, mangeaizan !
Marsh Posté le 06-01-2006 à 16:32:52
Vais refaire la même chose avec Oracle (en ajoutant le MINUS aussi)
Sauf que le souci, c'est que je ne peux pas faire d'Explain Plan, j'ai pas les droits nécessaire...
Code :
|
=> 1201 en 500 ms
Code :
|
=> 1201 en 2 minutes 31 secondes
Code :
|
=> 1201 en 2 minutes et 28 secondes
Code :
|
(ma version d'Oracle (8.1.7) ne supporte pas la syntaxe "left outer join" )
=> 1201 en 4 minutes 16 secondes
Y'a pas à dire, Oracle c'est vraiment de la merde en branche
Certes, y'a un peu de monde qui bosse dessus mais quand même !
Les deux bases ont des volumes similaires (j'ai backup sur mon portable la base Oracle il y a quelques mois avec SQL Server)
Quand je pense que mon portable est plus rapide qu'un bi-xéon boosté
Peut-être un problème d'indexes... Pourtant logiquement ceux qui existent devraient être utilisés là...
M'enfin quand même... L'outil qui est utilisé avec Oracle fait des locks, c'est pas possible autrement, mes requêtes ont dû être bloquées... Referai le test cette nuit quand y'aura plus personne.
En tout cas, le coup du MINUS me laisse perplexe ! Domage qu'on ne puisse pas l'utiliser plus souvent ! (usage limité, et surtout, supporté par presque aucun SGBD...)
Marsh Posté le 06-01-2006 à 22:35:38
bizzare tes temps de réponse. Oracle est quand mm bcp utilisé auprès des grosses entreprises. C'est dommage que je n'ai pas une base avec autant de lignes, sinon j'aurais fait le test en 10g
Marsh Posté le 06-01-2006 à 23:22:49
moi23372 a écrit : bizzare tes temps de réponse. Oracle est quand mm bcp utilisé auprès des grosses entreprises. C'est dommage que je n'ai pas une base avec autant de lignes, sinon j'aurais fait le test en 10g |
ça n'empeche pas que ce soit de la merde en branches
je dirais même que ça m'étonne même pas, c'est toujours la merde qui se vend le mieux
Marsh Posté le 07-01-2006 à 16:37:57
Harkonnen a écrit : ça n'empeche pas que ce soit de la merde en branches |
c'est ton opinion, moi personnellement d'après mon expérience, oracle ma paru de loin plus accessible pour mes besoins que les autres! SQL Server je regrette sa complexité parfois au niveau de certaines fonctionalité, MySQL, ben il y a pas grand chose, et les autres j'ai pas encore eu l'occas, je testerais bien uen fois POSTgreSQL
Marsh Posté le 07-01-2006 à 19:30:29
Tu trouves SQL Server plus complèxe que Oracle ???
C'est le monde à l'envers
Marsh Posté le 08-01-2006 à 10:13:46
En tt cas la version 2005 oui... de plus, ayant été à la présentation de SQL SERVER 2005 en belgique, les gens de microsoft prétendait avoir inventé XMLDB (alors que ça a été crée par W3C, et que ORACLE l'implémente depuis déjà la version 9iR2)... Niveau fonctionnalité, SQL SERVER c'est pas encore ça...
Marsh Posté le 09-01-2006 à 21:10:50
Voici ma requête finale : est-ce que vous pourriez m'aider à l'alléger SVP ?
Code :
|
J'ai pas réussi à la faire avec un "not exists", ça ne voulait pas fonctionner et je n'arrive pas à l'adapter à un "left join" (je n'arrive pas à comprendre le fonctionnement, donc si vous avez un tuto, je suis preneur ).
Marsh Posté le 09-01-2006 à 23:16:15
Code :
|
Marsh Posté le 10-01-2006 à 09:15:56
Beegee a écrit :
|
J'ai testé, mais ça ne fonctionne pas :
Code :
|
Marsh Posté le 10-01-2006 à 09:23:14
Essaye plutôt comme ça :
Code :
|
j'avais oublié de mettre le nom du champ dans le NOT EXISTS.
Aliaser la table forum_sujets avec fs est nécessaire pour pouvoir l'utiliser dans la sous-requête.
Marsh Posté le 10-01-2006 à 10:14:07
Je viens de tester ta requête telle quelle :
#1109 - Unknown table 'forum_sujets' in field list
C'est pour ça que j'avais remplacé le "fs." par "forum_sujets."
EDIT : il fallait remplacer "forum_sujets." dans la requete principale par "fs." et maintenant ça fonctionne
Merci beaucoup
Marsh Posté le 10-01-2006 à 10:40:40
De rien (ça doit être une limitation de mySql, il me semble que sous Oracle, même si une table est aliasée, si ce n'est pas ambigu, on peut toujours utiliser le nom de la table ...).
Marsh Posté le 10-01-2006 à 10:41:38
Bonjour.
J'ai trouvé ce thread en cherchant de l'aide et j'ai essayé d'appliquer la solution proposé au début avec un left outer join, mais maintenant ma requète ne me renvoi plus rien alors que les données semblent êtres bonnes. Si vous pouviez juste me dire si vous remarquez qqchose de travers ce serait sympa car je commence légérement à devenir fou
Cette requète a pour but de retrouver les identifiants de tous les utilisateurs valides avec date_modif > 1an et qui n'apparaissent pas dans la table relances.
Je tourne sous MySql 4.0.24 (important, y a encore bcq de trucs qui marchent pas sous cette version).
voilà ma requète :
Code :
|
Marsh Posté le 10-01-2006 à 11:40:00
humm... qqun aurait une corde sur lui?
je suis dégouté que ce soit si peu de choses mais en tous cas ca marche! merci bcq beegee!
Marsh Posté le 10-01-2006 à 12:02:30
Beegee a écrit : De rien (ça doit être une limitation de mySql, il me semble que sous Oracle, même si une table est aliasée, si ce n'est pas ambigu, on peut toujours utiliser le nom de la table ...). |
Nope, Oracle plante aussi. SQL Server par contre, il s'en contre-fou comme de l'an 40
Marsh Posté le 11-01-2006 à 16:23:24
Plus simplement, il suffirais d'ajouter une colonne de plus indiquant le nombre deconsultation; que tu mettra a jour à partir d'un count de la table des consultations. Alors ta requette de consultation s'allege puisqu'il suffira de sélectionner les articles qui ont une consultation = à 0.
Marsh Posté le 21-01-2006 à 09:52:22
Bonjour, j'ai encore un problème avec une requête qui fonctionnait chez Free, mais qui ne fonctionne plus chez OVH
La voici :
Code :
|
Voici l'erreur qui m'est retournée :
#1064 - You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT id_cage FROM cochon WHERE id_cage =3984 AND mort =0 ) LI
Auriez-vous une idée d'où cela peut-il venir ?
Est-ce possible, en passant, d'optimiser cette requête ?
Merci d'avance
Marsh Posté le 21-01-2006 à 11:08:41
La version de mySql doit être plus ancienne, et ne doit pas permettre les sous-requêtes.
Tu peux à la place utiliser une jointure externe :
Code :
|
Marsh Posté le 21-01-2006 à 12:15:50
Beegee a écrit : La version de mySql doit être plus ancienne, et ne doit pas permettre les sous-requêtes.
|
Merci beaucoup, ça fonctionne
La version de MySQL est la 4.7, c'est bizarre quand même que le "not in" ne fonctionnait pas
EDIT: au final, ça ne me retourne pas le résultat comme convenu
Au lieu de me retourner 1 champ, ça m'en retourne 0.
Marsh Posté le 02-09-2010 à 11:40:40
c'est MySQL la merde si tu compares à Oracle
Oracle en base de données c'est le top, mais encore faut-il savoir construire ses requêtes petit scarabée
quand tu effectues un SELECT multi table (avec des jointures) il faut mettre les tables les plus importantes à la fin du FROM
si TABLE1 est la table principale qu'elle fait des jointures avec TABLE2 et TABLE3 alors fait
SELECT t1.champ1, t1.champ2, t2.champ1
FROM TABLE3 T3, TABLE2 T2, TABLE1 T1
WHERE T1.champ1=T2.champ2
and T1.champ1=T3.champ3
L'ordre des jointures dans le where n'est pas important, mais pour des requêtes volumineuses mieux vaut bien les structurer pour ne mas s'y perdre
Marsh Posté le 02-09-2010 à 14:00:02
Je crois qu'en 4 ans il a compris ...
Et l'optimisateur de query se charge tres bien d'organiser les tables, peut importe l'ordre dans la query ...
Marsh Posté le 03-09-2010 à 07:40:45
...et pour pas s'y perdre il faut éviter cette syntaxe de jointures dans le where qui date de l'avant-guerre, pour commencer.
Marsh Posté le 05-09-2010 à 21:08:49
gorgorbhey a écrit : |
gorgorbhey a écrit : |
Marsh Posté le 06-01-2006 à 12:37:35
Bonjour,
J'ai une requête que je trouve très lourde et je voudrais savoir comment je peux l'optimiser.
Voici la requête :
En gros, la table forum_messages contient tous les posts du forum et la table forum_lu sert à stocker les messages lus.
Je voudrais donc obtenir la liste des messages qui n'ont jamais été lus.
Existe-t-il un moyen d'obtenir ce résultat autrement qu'avec un NOT IN ?
Merci d'avance
Message édité par nero27 le 06-01-2006 à 12:38:29