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

 


 Mot :   Pseudo :  
 
 Page :   1  2  3  4
Auteur Sujet :

[résolu] Besoin d'aide pour écrire une requête SQL compliquée

n°1476181
MagicBuzz
Posté le 16-11-2006 à 09:35:59  profilanswer
 

Reprise du message précédent :
sinon, le coup du MATCH pour retrouver des mots exacts, je suis pas certain que ce soit une super idée. MATCH (et dérivés) ça sert à faire des moteurs de recherche tapant dans de gros volumes d'infos. dans ton cas, ça me semble peu justifié, et surtout, MATCH peut faire de l'approximation d'orthographe, ce que tu ne veux pas forcément.

mood
Publicité
Posté le 16-11-2006 à 09:35:59  profilanswer
 

n°1476217
rufo
Pas me confondre avec Lycos!
Posté le 16-11-2006 à 10:24:09  profilanswer
 

MagicBuzz a écrit :

sinon, le coup du MATCH pour retrouver des mots exacts, je suis pas certain que ce soit une super idée. MATCH (et dérivés) ça sert à faire des moteurs de recherche tapant dans de gros volumes d'infos. dans ton cas, ça me semble peu justifié, et surtout, MATCH peut faire de l'approximation d'orthographe, ce que tu ne veux pas forcément.


 
oui, effectivement, je veux les valeurs exactes recherchées et non des approximations.

n°1476228
rufo
Pas me confondre avec Lycos!
Posté le 16-11-2006 à 10:36:31  profilanswer
 

MagicBuzz a écrit :

pour ces trucs là, je pense que le mieux, c'est de faire une requête "toute bête" qui ramène l'intégralité des attributs d'une config.
la lancer pour chacune des deux configs.
puis comparer dans ton appli, ou à la limite dans une procédure stockée.
mais en requête, à mon avis tu vas être hyper limité (trop de cas possibles, donc complexité accrue de ta requête) d'autant plus que pour l'affichage, tu risques de vouloir aussi les attributs communs.


 
mon appli est en PHP. Je ne pense pas me tromper en disant qu'une requête sql, c'est plus rapide que l'execution d'une script php... Et y'a pas tant que ça de cas de figures :
Conf 2 a par rapport à conf 1 :  
- des composants en +
- au sein d'un composant identique, des attributs  en +
- des composants en -
- au sein d'un composant identique, des attributs  en -
- au sein d'un composant identique, des attributs ayant des noms identiques mais des valeurs différentes.
 
Je le fais pour l'instant en 3 requêtes (qui sont optimisables). Et surtout, y'a moyen de trier les composants. Chaque composant est lié à un mot-clé donc, des composants sont identiques s'ils sont liés au même mot-clé. A part pour la comparaison des attributs de même nom mais de valeur différente, il n'y a pas besoin de descendre au niveau des nom et des valeurs d'attributs. Juste en travaillant sur les clés primaire, ça suffit. Il ne faut pas oublier qu'un attribut qui a le même nom, la même valeur, le même type et le même type de comparaison n'est pas dupliqué dans la base. Ca facilite donc le travail.
 
 
 

n°1476236
ratibus
Posté le 16-11-2006 à 11:15:46  profilanswer
 

rufo a écrit :

une dernière question : c'est vrai que pour MySQL, mettre un index sur un champ où on utilise LIKE, ça ne sert à rien car LIKE n'utilise pss les index?


Quelle version de MySQL ?

n°1476302
rufo
Pas me confondre avec Lycos!
Posté le 16-11-2006 à 13:02:04  profilanswer
 

la 5.0.22

n°1476396
ratibus
Posté le 16-11-2006 à 14:18:15  profilanswer
 

Citation :

A B-tree index can be used for column comparisons in expressions that use the =, >, >=, <, <=, or BETWEEN  operators. The index also can be used for LIKE comparisons if the argument to LIKE is a constant string that does not start with a wildcard character. For example, the following SELECT statements use indexes:
 
SELECT * FROM tbl_name WHERE key_col LIKE 'Patrick%';
SELECT * FROM tbl_name WHERE key_col LIKE 'Pat%_ck%';
 
In the first statement, only rows with 'Patrick' <= key_col < 'Patricl' are considered. In the second statement, only rows with 'Pat' <= key_col < 'Pau' are considered.
 
The following SELECT statements do not use indexes:
 
SELECT * FROM tbl_name WHERE key_col LIKE '%Patrick%';
SELECT * FROM tbl_name WHERE key_col LIKE other_col;
 
In the first statement, the LIKE value begins with a wildcard character. In the second statement, the LIKE value is not a constant.
 
If you use ... LIKE '%string%' and string is longer than three characters, MySQL uses the Turbo Boyer-Moore algorithm to initialize the pattern for the string and then uses this pattern to perform the search more quickly.


http://dev.mysql.com/doc/refman/5. [...] dexes.html
 
Sinon ensuite il y a la technique suivante : tu ajoutes un champ (appelons-le champ_reverse) avec les lettres à l'envers et tu requetes comme ça :

Code :
  1. WHERE champ LIKE 'valeur%' OR champ_reverse LIKE 'ruelav%'

T'as pas les mêmes résultats qu'avec le %valeur% mais après ça dépend de tes besoins fonctionnels ;)


Message édité par ratibus le 16-11-2006 à 14:24:05
n°1476429
MagicBuzz
Posté le 16-11-2006 à 14:35:22  profilanswer
 

ratibus >
La souci, c'est que Rufo utilise les LIKE pour des requêtes autogénérées. Donc les % seront toujours de chaque coté du mot cherché.
Et ensuite, la dernière technique ne marche pas du tout comme un %valeur% :spamafote:
 

n°1476482
rufo
Pas me confondre avec Lycos!
Posté le 16-11-2006 à 15:07:59  profilanswer
 

J'ai pas forcément les % de chaque côté puisque ça dépend de ce que va saisir l'utilisateur mais c'est vrai que dans la majorité des cas, ils y seront.
 
Par contre, j'ai pas compris l'intérêt du like avec les lettres à l'envers???

n°1476486
MagicBuzz
Posté le 16-11-2006 à 15:09:36  profilanswer
 

moi non plus. ça permet juste de chercher les trucs qui "terminent par". mais en aucun cas son truc permet de trouver "qui contient".
("qui contient" != "comment par" || "termine par" )

n°1476559
fred777888​999
Posté le 16-11-2006 à 15:45:48  profilanswer
 

En primes, optimiser une requete qui contient un like %truc% par une requete qui contient un OR est une notion pour le moins amusante.
Peut etre avec un union on peut faire mieux, mais avec un OR sauf si mysql le transforme de lui meme en deux requetes (auquel cas autant le faire toi, tu evite de donner pour rien du boulot a l'optimiseur), c'est tres tres mal barre.  :ange:
Pour le like, ce n'est pas vrai que les index ne sont pas utilises, simplement, ils sont utilises 'au mieux'.
Il faut voir un index comme le tri alphabetique d'un dictionnaire.  
Quand tu cherche dans un dico tous les mots like 'AB%', l'ordre alphabetique est utile et donc ton index est utilise (en partie, car tu te farcit a la mano un grand nombre de mots, mais si t'est pas trop polio, pas tout le dico), par contre si tu cherche tout ceux like '%AB%', c'est a dire qui contiennent AB, tu n'as plus rien a foutre que ce soit classe par ordre alpha car tu est oblige de te palucher tout le contenu. Le moteur de BDD fonctionne comme ca lui aussi.  :ange:

mood
Publicité
Posté le 16-11-2006 à 15:45:48  profilanswer
 

n°1476610
ratibus
Posté le 16-11-2006 à 16:06:36  profilanswer
 

rufo a écrit :

J'ai pas forcément les % de chaque côté puisque ça dépend de ce que va saisir l'utilisateur mais c'est vrai que dans la majorité des cas, ils y seront.
 
Par contre, j'ai pas compris l'intérêt du like avec les lettres à l'envers???


L'intéret du champ avec les lettres à l'envers c'est que l'index est un BTREE donc étant donné la structure d'un BTREE, l'index ne peux être utilisé pour une recherche du type %valeur. Par contre si t'as un champ avec les lettres à l'envers tu peux transformer le LIKE %valeur en champ_reverse LIKE ruelav% et du coup ça utilise l'index ;)
http://jcole.us/blog/mysql/calcula [...] -mysql-50/

MagicBuzz a écrit :

moi non plus. ça permet juste de chercher les trucs qui "terminent par". mais en aucun cas son truc permet de trouver "qui contient".
("qui contient" != "comment par" || "termine par" )

Oui je sais, c'est pas ce qui est marqué dans mon message ;) (j'ai édité j'avais fait une boulette).
 

fred777888999 a écrit :

En primes, optimiser une requete qui contient un like %truc% par une requete qui contient un OR est une notion pour le moins amusante.
Peut etre avec un union on peut faire mieux, mais avec un OR sauf si mysql le transforme de lui meme en deux requetes (auquel cas autant le faire toi, tu evite de donner pour rien du boulot a l'optimiseur), c'est tres tres mal barre.  :ange:
Pour le like, ce n'est pas vrai que les index ne sont pas utilises, simplement, ils sont utilises 'au mieux'.
Il faut voir un index comme le tri alphabetique d'un dictionnaire.  
Quand tu cherche dans un dico tous les mots like 'AB%', l'ordre alphabetique est utile et donc ton index est utilise (en partie, car tu te farcit a la mano un grand nombre de mots, mais si t'est pas trop polio, pas tout le dico), par contre si tu cherche tout ceux like '%AB%', c'est a dire qui contiennent AB, tu n'as plus rien a foutre que ce soit classe par ordre alpha car tu est oblige de te palucher tout le contenu. Le moteur de BDD fonctionne comme ca lui aussi.  :ange:

Pour le OR sur des champs distinct (sur un même champ ça n'a jamais posé de souci à MySQL), c'est bon en version 5 (http://dev.mysql.com/doc/refman/5.0/en/searching-on-two-keys.html) plus besoin de splitter avec des UNIONS ;)


Message édité par ratibus le 16-11-2006 à 16:08:35
n°1476628
fred777888​999
Posté le 16-11-2006 à 16:19:38  profilanswer
 

:jap: Oki, bon a savoir, j'ai tj trouve la manip un peu lourde avec les union, mais il est vrai qu'en general quand on a une requete avec des ors, c'est souvent qu'on a une jointure mal faite (mal modelisee en general je precise, le dev y est rarement pour qq chose) et c'est alors rarement vraiment optimisable.
Sinon franchement le jour ou je vois qq qui utilise ton astuce avec le champ reverse pour optimiser une recherche, il a 99% de chances de se prendre une bonne soufflee pour avoir modelise comme un manche au lieu d'avoir fait une table de mots clefs, mais apres comme tu le dis, ca depends des besoins fonctionnels et il y a peut etre un cas sur 100 ou il aura raison  :ange:

n°1476714
ratibus
Posté le 16-11-2006 à 17:21:56  profilanswer
 

Et là c'est lui qui t'allume :D

n°1477093
rufo
Pas me confondre avec Lycos!
Posté le 17-11-2006 à 11:05:55  profilanswer
 

Ca serait intéressant de faire un classement sur le temps d'exécution des instructions SQL (celles qui consomment le - à celles qui consomment le +).
Comment instructions, on a :
- DISTINCT
- MIN, MAX, COUNT, AVG...
- JOIN (inner, outer, left, right...)
- AND et OR
- LIKE et MATCH
- IN, EXISTS, ALL, SOME et ANY
- UNION
- GROUP BY
- HAVING
- ORDER BY
- LIMIT
 
ps : j'ai pas mis SELECT ni FROM car je ne sais pas si ça rentre en ligne de compte dans le temps d'exécution...


Message édité par rufo le 17-11-2006 à 11:07:03
n°1477248
MagicBuzz
Posté le 17-11-2006 à 12:16:31  profilanswer
 

c'est 100% dépendant de ce que tu fais avec et des volumes de données.
 
dans certaines cas, une bidouille gore pour éviter un UNION va faire gagner du temps, et des fois, la même bidouille dans une requête différente ou un volume différent, va faire perdre du temps.
 
ensuite, d'un SGBD à l'autre, le bench ne sera pas valable.

n°1477289
rufo
Pas me confondre avec Lycos!
Posté le 17-11-2006 à 13:10:33  profilanswer
 

je parlais d'une manière générale. Y'a quand même des tendances.
Ex : un LIKE %...% est plus gourmand qu'un champ = "..." ou un inner join est plus rapide qu'un IN(...)

n°1478330
rufo
Pas me confondre avec Lycos!
Posté le 20-11-2006 à 11:27:54  profilanswer
 

au niveau perfs, il vaut mieux faire :
SELECT ... FROM table1 INNER JOIN table2 ON table1.id = table2.id WHERE...
 
ou
 
SELECT ... FROM table1, table2 WHERE table1.id = table2.id AND...

n°1478365
MagicBuzz
Posté le 20-11-2006 à 12:18:33  profilanswer
 

Normalement ça change queud.
Je suis à la base plutôt partisant du second, qui est plus lisible je trouve (et qui a l'avantage de passer quelquesoit le SGBD), mais le second permet de faire certaines choses impossibles avec le premier. Mais l'inverse est vrai aussi alors...

n°1478398
rufo
Pas me confondre avec Lycos!
Posté le 20-11-2006 à 12:52:49  profilanswer
 

MagicBuzz a écrit :

Normalement ça change queud.
Je suis à la base plutôt partisant du second, qui est plus lisible je trouve (et qui a l'avantage de passer quelquesoit le SGBD), mais le second permet de faire certaines choses impossibles avec le premier. Mais l'inverse est vrai aussi alors...


 
peut-être que dans le 1er cas, ça permet de réduire le nb d'enregistrements et de ce fait, la clause where s'executera plus vite...


Message édité par rufo le 20-11-2006 à 12:53:03
n°1478422
MagicBuzz
Posté le 20-11-2006 à 13:55:35  profilanswer
 

ben ça réduit rien du tout. la jointure est la même, et elle sera effectuée par le moteur de la même façon.
la seule réelle différence, c'est qu'expliciter le "inner join", c'est expliquer au moteur de requête comment faire la requête.
donc si on l'écrit comme un âne, ça peut être plus lent que de ne pas utiliser le inner, alors que si on l'écrit correctement, c'est la garantie que le moteur fera correctement son boulot.
mais à la base, pour planter l'optimiseur, faut déjà lui balourder une sacrée requête.

n°1478431
MagicBuzz
Posté le 20-11-2006 à 14:02:32  profilanswer
 

Ici, tu trouveras un petit bench sous Oracle 8i, où je mets en valeur ce que je te dis ici : sous prétexte que le nombre de lignes à analyser est plus grand, on ne peut pas prétendre quoi que ce soit.
 
Dans l'exemple, plus la requête est compliqué, et plus il y a de jointures, plus elle est rapide.
 
C'est pour cette raison que je me refuse à faire le moindre pronostique sur la vitesse d'une requête, où dire qu'un inner est plus rapide qu'une jointure implicite : ça dépend de bien trop d'autres paramètres dans la requête pour pouvoir faire la moindre conclusion.
 
Les seules choses qu'on puisse affirmer à coup sur :
- Le IN, s'il est utilisé pour faire une sous-requête, sera TOUJOURS moins performant qu'un EXISTS
- La fioriture (champ1, champ2) in (select champ1, champ2 ...) est toujours remplaçable par un EXISTS qui sera toujours infiniment plus rapide
- Un GROUP BY utilisé simplement pour faire un tri est plus lent qu'un ORDER BY
- Un DISTINCT afin de filtrer les doublons est généralement plus lent qu'une sous-requête (EXISTS ?) permettant de s'affranchir des doublons
- Un UNION est toujours à remplacer par UNION ALL quand il n'y a pas de doublons
 
C'est tout ce que je peux affirmer, et qui est vrai "à coup sûr".
Ces affirmations ne reposent que sur une analyse sémantique de la syntaxe SQL (sauf pour le DISTINCT). Les clauses ne sont à utiliser que pour ce pour quoi elles sont prévues. Notamment le IN, c'est pas pour faire une jointure, mais pour faire une énumération (donc il ne faut jamais y trouver autrechose qu'une liste énumérée, jamais une requête)
 
http://forum.hardware.fr/forum2.ph [...] 0#t1447077


Message édité par MagicBuzz le 20-11-2006 à 14:02:46
n°1478470
rufo
Pas me confondre avec Lycos!
Posté le 20-11-2006 à 14:29:27  profilanswer
 

Merci pour ces infos.
 
Je l'avais lu ton topic sur les SGBD, ça m'avait bien intéressé.
 
Au fait, je ne comprend pas l'intérêt de faire un "SELECT null FROM table WHERE..."
 
exemple pris dans ton sujet :  

Code :
  1. select 
  2.   c1.cli_id, c1.cmd_id, convert(varchar, c2.cmd_date - c1.cmd_date, 108)
  3. from t_commande c1 left outer join t_commande c2 on c1.cli_id = c2.cli_id and c1.cmd_id < c2.cmd_id
  4. where c2.cmd_id = (select min(c3.cmd_id) from t_commande c3 where c3.cli_id = c1.cli_id and c3.cmd_id > c1.cmd_id)
  5. or (c2.cmd_id is null and not exists (select null from t_commande c4 where c4.cli_id = c1.cli_id and c4.cmd_id < c1.cmd_id))

n°1478517
MagicBuzz
Posté le 20-11-2006 à 15:17:44  profilanswer
 

"select null from table" c'est pour le EXISTS.
 
EXISTS permet de tester la validité d'une jointure (et donc ne fait pas de traîtement sur le résultat de la sous-requête). Le "select null" permet donc de s'assurer qu'on ne joue pas avec des données en mémoire pour rien.
 
Exemple avec Oracle 10g R2.
 
Tu veux le nom de tous les clients qui ont passé au moins une commande de vente :
 
Classique :


select distinct t.sigtie, t.nomtie  
from tie t inner join eve e on e.codsoc = t.codsoc and e.typtie = t.typtie and e.sigtie = t.sigtie and e.achvte = 'V' and e.typeve = 'CDV'
where t.codsoc = 2  
and t.typtie = 'CLI'  


Entre 280 et 400 ms pour 137 lignes
 
Seul hic : y'a un distinct, et c'est mal.
 
Avec EXISTS :


select t.sigtie, t.nomtie  
from tie t  
where t.codsoc = 2  
and t.typtie = 'CLI'  
and exists  
(  
  select null  
  from eve e  
  where e.codsoc = t.codsoc  
  and e.typtie = t.typtie  
  and e.sigtie = t.sigtie  
  and e.achvte = 'V'  
  and e.typeve = 'CDV'  
)


Entre 30 et 50 ms pour 137 lignes
 
Y'a plus de DISTINCT. Et vu que la sous-requête se contente de faire une jointure "toute bête", elle est beaucoup plus rapide que la première (et pourtant, à première vue, elle ne l'est pas du tout).
 
Pour confirmer ce que je dis à propos des généralités non généralisables, ici, l'optimiseur transforme le IN en EXISTS : rigoureusement le même temps de traîtement) :
 


select t.sigtie, t.nomtie  
from tie t  
where t.codsoc = 2  
and t.typtie = 'CLI'  
and t.sigtie in  
(  
  select e.sigtie
  from eve e  
  where e.codsoc = t.codsoc  
  and e.typtie = t.typtie  
  and e.sigtie = t.sigtie  
  and e.achvte = 'V'  
  and e.typeve = 'CDV'  
)


Entre 30 et 50 ms pour 137 lignes
 
Chose étrange pour les idées reçues : une requête bien écrite, même si elle est plus complexe, est plus rapide qu'une requête "simple" mais mal pensée.
 
Mieux : Je veux le nom de tous les clients qui n'ont pas commandé :
 
Classique :


select t.sigtie, t.nomtie, count(e.numeve)
from tie t left outer join eve e on e.codsoc = t.codsoc and e.typtie = t.typtie and e.sigtie = t.sigtie and e.achvte = 'V' and e.typeve = 'CDV'
where t.codsoc = 2  
and t.typtie = 'CLI'  
group by t.sigtie, t.nomtie
having count(e.numeve) = 0


Entre 500 et 900  ms pour 148 lignes
(Plus besoin du DISTINCT puisque je ne peux pas avoir plusieurs commandes pour un même client. Par contre, la jointure gauche est bien plus lente)
 
NOT EXISTS :


select t.sigtie, t.nomtie, t.typtie
from tie t  
where t.codsoc = 2  
and t.typtie = 'CLI'  
and not exists  
(  
  select null  
  from eve e  
  where e.codsoc = t.codsoc  
  and e.typtie = t.typtie  
  and e.sigtie = t.sigtie  
  and e.achvte = 'V'  
  and e.typeve = 'CDV'  
)


Entre 10 et 20 ms pour 148 lignes
 
Toujours pareil avec NOT IN (juste pour faire chier)


select t.sigtie, t.nomtie  
from tie t  
where t.codsoc = 2  
and t.typtie = 'CLI'  
and t.sigtie not in  
(  
  select e.sigtie
  from eve e  
  where e.codsoc = t.codsoc  
  and e.typtie = t.typtie  
  and e.sigtie = t.sigtie  
  and e.achvte = 'V'  
  and e.typeve = 'CDV'  
)


Entre 10 et 20 ms pour 148 lignes
 
A noter ici qu'avec le 10g, Oracle semble avoir fait une énorme correction en ce qui concerne l'optimiseur. Avec la 8i, la requête avec le IN aurait pris plusieurs dizaines de secondes.


Message édité par MagicBuzz le 20-11-2006 à 15:22:27
n°1478523
MagicBuzz
Posté le 20-11-2006 à 15:21:26  profilanswer
 

Nota : En fait, pour le "IN" qui est rapide ici, je soupçonne, plutôt qu'une grosse optimisation, que je tombe juste dans un cas où le IN n'impacte pas tro les perfs : en effet, la liste des "sigtie" est très petite, donc même si Oracle s'amuse à construire la liste puis la tester pour chaque ligne de TIE, alors cela n'influe pas ou peu au niveau performances.

n°1478541
rufo
Pas me confondre avec Lycos!
Posté le 20-11-2006 à 15:42:19  profilanswer
 

je ne connais pas le modèle de ta BD, mais comment ça se fait qu'avec cette requête là, du coup, t'as plus de doublon par rapport à la première requête de ton précédent post?

Code :
  1. select t.sigtie, t.nomtie 
  2. from tie t 
  3. where t.codsoc = 2 
  4. and t.typtie = 'CLI' 
  5. and exists 
  6.   select null 
  7.   from eve e 
  8.   where e.codsoc = t.codsoc 
  9.   and e.typtie = t.typtie 
  10.   and e.sigtie = t.sigtie 
  11.   and e.achvte = 'V' 
  12.   and e.typeve = 'CDV'

Message cité 1 fois
Message édité par rufo le 20-11-2006 à 15:42:53
n°1478542
MagicBuzz
Posté le 20-11-2006 à 15:42:49  profilanswer
 

:heink:
 
arf, je viens de piger pour le IN...
 


select t.sigtie, t.nomtie  
from tie t  
where t.codsoc = 2  
and t.typtie = 'CLI'  
and t.sigtie in  
(  
  select e.sigtie  
  from eve e  
  where e.codsoc = t.codsoc  
  and e.typtie = t.typtie  
  and e.sigtie = t.sigtie  
  and e.achvte = 'V'  
  and e.typeve = 'CDV'  
)


 
Et
 


select t.sigtie, t.nomtie  
from tie t  
where t.codsoc = 2  
and t.typtie = 'CLI'  
and t.sigtie not in  
(  
  select e.sigtie  
  from eve e  
  where e.codsoc = t.codsoc  
  and e.typtie = t.typtie  
  and e.sigtie = t.sigtie  
  and e.achvte = 'V'  
  and e.typeve = 'CDV'  
)  


 
Ceci dit, pour la première, ça change peau de cacahuète.
Mais pour la seconde, on passe à 3 secondes ! (donc IN, caca boudin prout prout)

n°1478545
MagicBuzz
Posté le 20-11-2006 à 15:45:06  profilanswer
 

rufo a écrit :

je ne connais pas le modèle de ta BD, mais comment ça se fait qu'avec cette requête là, du coup, t'as plus de doublon par rapport à la première requête de ton précédent post?


 
Ben parceque lis la requête :o
 
La première, je fais une jointure "toute bête" entre les clients et les commandes. Donc si un client commande 25 fois, je vais avoir 25 fois le client dans mon résultat.
 
La seconde, je prend la liste des clients, et pour chacun, je regarde s'il a passé des commandes (sans récupérer les commandes).
Donc je n'ai plus de doublon.
Et en plus, c'est plus rapide, puisque dès que je trouve une commande, je peux passer au client suivant, alors qu'avec la jointure classique, je dois récupérer toutes les commandes de chaque client.

n°1478547
rufo
Pas me confondre avec Lycos!
Posté le 20-11-2006 à 15:45:26  profilanswer
 

au fait, c'est quoi pour toi "une requête bien pensée"? Bien pensée selon les specs du SQL ou selon la façon dont fonctionne le sgbd?

n°1478549
MagicBuzz
Posté le 20-11-2006 à 15:49:15  profilanswer
 

Pour le IN, avec cette requête c'est probant (evp est plutôt conséquente) :
 


select *
from pro
where pro.codsoc = 2
and not exists
(
  select null
  from evp
  where evp.codsoc = pro.codsoc
  and evp.achvte = 'V'
  and evp.typeve = 'CDV'
  and evp.codpro = pro.codpro
)


400 - 500 ms pour choper les premières lignes. Les 1501 lignes se chargent en un temps négligeable (moins de 1 seconde)
 


select *
from pro
where pro.codsoc = 2
and pro.codpro not in
(
  select evp.codpro
  from evp
  where evp.codsoc = pro.codsoc
  and evp.achvte = 'V'
  and evp.typeve = 'CDV'
)


1300 ms pour choper les premières lignes. Les 1501 lignes mettent plus d'une minute à charger.
 
Donc, IN = abomination à exclure de son vocabulaire SQL :o

n°1478550
MagicBuzz
Posté le 20-11-2006 à 15:53:22  profilanswer
 

rufo a écrit :

au fait, c'est quoi pour toi "une requête bien pensée"? Bien pensée selon les specs du SQL ou selon la façon dont fonctionne le sgbd?


Ni l'un ni l'autre : une requête qui fait correctement ce qu'on lui dit, de la façon la plus naturelle possible.
 
"Je veux la liste de tous les clients qui ont passé au moins une commande", ça se traduit en français par "Je veux la liste de tous les clients pour lesquels il existe au moins une commande" et non "Je veux le nom des clients qui ont passé toutes les commandes de la base sans répétition".
 
Donc on écrit avec un EXISTS et non une jointure.
 
Le SQL, y'a pas plus simple : tu traduis bêtement ce qu'on te demande de trouver, et tu trouveras la requête la plus optimisée possible du premier coup dans 99% des cas.
 
Ensuite, les SGBD tentent de pallier aux inepties des utilisateurs, mais en aucun cas ne peuvent faire mieux que meilleur. Dans le meilleur des cas, donc, ils vont traduire une requête écrite n'importe comment en une requête "propre". C'est ce que semble faire Oracle 10g avec le IN et le EXISTS. Par contre, il ne s'en sort pas du tout avec le NOT IN à remplacer par NOT EXISTS.
 
Dans tous les cas, quelque soit le SGBD, tu écrit "proprement" la requête du premier coup, et quelles que soient les spécificitées du SGBD tu auras le meilleur résultat possible. (je ne parle pas des petits SGBD non évolués, où chaque instruction n'a pas été travaillée autant que les ténors du marché Oracle, SQL Server, DB2, MySQL, etc.)


Message édité par MagicBuzz le 20-11-2006 à 15:54:32
n°1478552
MagicBuzz
Posté le 20-11-2006 à 15:56:11  profilanswer
 

Ensuite, comme je viens de dire dans le post précédent, utiliser "EXISTS" pour "je veux le nom de tous les clients qui ont commandé", ça respecte tout autant la norme SQL que faire ue jointure et boucher les trous à coup de rustines comme le DISTINCT. A la base, un DISTINCT dans une requête, c'est qu'on a mal écrit sa requête. Il n'est là que pour pallier à des erreurs d'analyse.

n°1479129
rufo
Pas me confondre avec Lycos!
Posté le 21-11-2006 à 11:33:47  profilanswer
 

Bon, je galère grave pour écrire mes 3 requêtes destinées à retourner les attributes en +, en - ou de valeur <> entre 2 configurations (je compare les différences entre 2 confs). Petit rappel de mes tables :  
Configurations (ConfigurationID, ConfigurationName, ConfigurationDate, ConfigurationVersion, ConfigurationInternalVersion, ConfigurationParentID)
Components (ComponentID, ConfigurationID)
CmpKeyWordsComponents (CmpKeyWordComponentID, ComponentID, CmpKeyWordID)
ComponentsAttributes (ComponentAttributeID, ComponentID, AttributeID)
Attributes (AttributeID, AttributeName, AttributeType, AttributeValue, AttributeCompareType)
 
Qq règles :  
1) une configuration ayant sa version interne à 1 (la première version d'une famille de configurations) à ConfigurationParentID à NULL
2) une configuration ayant sa version interne > 1 à un ConfigurationParentID <> NULL
3) toutes les configurations d'une même famille ont le même ConfigurationParentID (à l'exception de la configuration parente qui a son ConfigurationParentID à NULL, cf. règle 1)
4) une configuration a des composants, 1 composant n'appartient qu'à une conf
5) un composant à des attributs
6) un attribut peut être partagé par plusieurs composants
7) comme un composant n'est qu'une collection d'attributs, pour distinguer le rôle fonctionnel d'un composant, je lui associe un mot-clé (ex : CPU). De ce fait, pour le calcul des attributs ayant le même nom mais une valeur différente, je le travaille que sur les composants qui ont le même mot-clé (sinon, ça reviendrait à comparer des choux avec des carottes :D)
 
Pour l'instant, voilà les 3 requêtes que j'ai écrites mais pas optimisées :  
Requête pour avoir les attributs en +


SELECT a2.AttributeID, ca2.ComponentID  
FROM Attributes a2, Components c2 INNER JOIN CmpKeyWordsComponents ckwc2 ON c2.ComponentID = ckwc2.ComponentID AND c2.ConfigurationID IN (1, 7)  
INNER JOIN ComponentsAttributes ca2 ON c2.ComponentID = ca2.ComponentID
WHERE ca2.AttributeID = a2.AttributeID  
AND a2.AttributeCompareType = 1
AND a2.AttributeName NOT IN (
                                          SELECT a.AttributeName  
                                          FROM ComponentsAttributes ca, Attributes a, Components c
                                          WHERE c.ConfigurationID = 1
                                          AND c.ComponentID = ca.ComponentID  
                                          AND ca.AttributeID = a.AttributeID  
                                          AND a.AttributeCompareType = 1
                                        )
ORDER BY ca2.ComponentID


 
Requête pour avoir les attributs en -


SELECT a3.AttributeID, ca3.ComponentID  
FROM Attributes a3, ComponentsAttributes ca3, Components c3, CmpKeyWordsComponents ckwc3
WHERE c3.ConfigurationID = 1
AND c3.ComponentID = ca3.ComponentID
AND c3.ComponentID = ckwc3.ComponentID
AND a3.AttributeID = ca3.AttributeID
AND a3.AttributeCompareType = 1
AND a3.AttributeName NOT IN  
                                        (
                                          SELECT a.AttributeName  
                                          FROM ComponentsAttributes ca, Attributes a, Components c
                                          WHERE c.ConfigurationID = 7
                                         AND c.ComponentID = ca.ComponentID
                                         AND ca.AttributeID = a.AttributeID
                                         AND a.AttributeCompareType = 1
                                       )
ORDER BY ComponentID


 
Requête pour avoir les attributs de même nom mais de valeur différente


SELECT a2.AttributeID, ca2.ComponentID
FROM Attributes a1, ComponentsAttributes ca1, Components c1, CmpKeyWordsComponents ckwc1, Attributes a2, ComponentsAttributes ca2, Components c2, CmpKeyWordsComponents ckwc2
WHERE c1.ConfigurationID = 1
AND c1.ComponentID = ca1.ComponentID
AND c1.ComponentID = ckwc1.ComponentID
AND a1.AttributeID = ca1.AttributeID
AND c2.ConfigurationID = 7
AND c2.ComponentID = ca2.ComponentID
AND c2.ComponentID = ckwc2.ComponentID
AND a2.AttributeID = ca2.AttributeID
AND ckwc1.CmpKeyWordID = ckwc2.CmpKeyWordID
AND a1.AttributeName = a2.AttributeName
AND a1.AttributeCompareType = 1
AND a2.AttributeCompareType = 1
AND a1.AttributeValue <> a2.AttributeValue
AND ca2.AttributeID NOT IN (
                                        SELECT DISTINCT ca3.AttributeID  
                                        FROM Components c3, ComponentsAttributes ca3, Attributes a3
                                        WHERE c3.ConfigurationID = 1
                                        AND c3.ComponentID = ca3.ComponentID
                                        AND ca3.AttributeID = a3.AttributeID
                                        AND a3.AttributeCompareType = 1
                                      )
ORDER BY ComponentID


 
ps1: Please, pas taper pour les IN. J'ai dû mal avec le EXISTS
 
ps2: mes requêtes ne fonctionnent pas dans tous les cas. En effet, si on a :
- CONF 1 a comme composition :  
      Composant "disquette" (mot-clé)
          Cmp1 (composant)
              Nom lecteur = fd0 (attribut avec son nom et sa valeur)
         Cmp2 (autre composant)
              Nom lecteur = fd1
 
- CONF 2 a comme composition :  
      Composant "disquette" (mot-clé)
          Cmp1 (composant)
              Nom lecteur = fd0 (attribut avec son nom et sa valeur)
           
Si je compare CONF 1 à CONF 2, je ne trouve pas de différence :(
Si je compare CONF 2 à CONF 1, je trouve que la CONF 2 a un attribut <> : Nom lecteur = fd1. Il ne me le compte pas en tant que composant en + :/
 
Donc, si tu as un peu de temps pour m'aider, je t'en remercie par avance :jap:


Message édité par rufo le 21-11-2006 à 11:38:52
n°1479135
MagicBuzz
Posté le 21-11-2006 à 11:38:33  profilanswer
 

Ben c'est pourtant simple.
 
Une requête de ce type :
 


select *
from table1
where table1.id in (select id from table2)


 
Peut se traduire de la sorte :
 


select *
from table1
where exists (select null from table2 where table2.id = table1.id)


 
Commence par mettre des EXISTS à la place de tes IN, ça devrait déjà améliorer les perfs.
 
Pour le reste, je suis malade là, chuis dans le gaz complet :cry:. A vrai dire, j'ai pas le courage de regarder tes requête :sleep:

n°1479147
rufo
Pas me confondre avec Lycos!
Posté le 21-11-2006 à 11:52:14  profilanswer
 

c'est pas urgent de toute manière. Si tu trouves un moment quand tu te seras rétabli...
 
Bon rétablissement en tout cas ;)

n°1479981
rufo
Pas me confondre avec Lycos!
Posté le 22-11-2006 à 15:45:56  profilanswer
 

un petit up...

n°1480219
MagicBuzz
Posté le 22-11-2006 à 19:55:58  profilanswer
 

tu peux poster un petit script de création de tes tables avec une dizaine de lignes de données de test ?
 
(genre deux configs qui rentrent dans les 3 cas)

n°1480233
MagicBuzz
Posté le 22-11-2006 à 20:06:09  profilanswer
 

A quoi servent les champs "ConfigurationDate, ConfigurationVersion" dans la table "Configurations" ?
 
A quoi sert ta table CmpKeyWordsComponents ? Comment t'en sers-tu ?
 
Le "AttributeType" dans "Attributes", c'est quoi ? Le type de la donnée qui est dedans, ou un type général (style CPU, Disque, etc.)

n°1480237
MagicBuzz
Posté le 22-11-2006 à 20:08:17  profilanswer
 

"ComponentAttributeID" est totalement inutile dans la table "ComponentsAttributes" à priori. A moins que tu veuilles permettre deux fois le même attribut pour un même composant, ce qui me semble étrange.

n°1480240
MagicBuzz
Posté le 22-11-2006 à 20:10:05  profilanswer
 

PS : T'es sûr que ton machin c'est pas une reprise de l'outils utilisé par Econocom ? Le truc, ils l'appellent euh... Mince, je ne me souviens plus. Un truc horrible, super mal designé et qui a une structre (et des noms de champs/tables à coucher dehors pareil que les tiens)... Mince, comment y s'appelle ce truc... Hmmm... "InterClass"

n°1480247
MagicBuzz
Posté le 22-11-2006 à 20:18:00  profilanswer
 

Ouais, c'est forcément InterClass... Le coup des attributs partagés... C'est pas possible autrement... Ton CP c'est pas un Monsieur Roche ?

n°1480250
MagicBuzz
Posté le 22-11-2006 à 20:25:19  profilanswer
 

Plus je réfléchis à ton machin, et plus je me dis qu'avec une telle structure c'est peine perdue... Là je vois pas du tout comment tu peux faire...
A la limite en haut niveau (PS ou code PHP). Et même là tu vas en chier un max...

mood
Publicité
Posté le   profilanswer
 

 Page :   1  2  3  4

Aller à :
Ajouter une réponse
 

Sujets relatifs
Résolu - Effacer des champs dans des tables à partir d'un select[RESOLU] PHP EXIF et retouche d'image
aide en c # sur une erreur CS01117[resolu] Probleme passage iframe --> include
Besoin d'une petite requette SQL[résolu] Prendre un nom de fichier + répertoire en macro pour excel
Aide En C++ Suite De Conway (Urgent!!!)[résolu...enfin presq]Choix multiple pour une propriété de type string
Authentification sans session. [Résolu] 
Plus de sujets relatifs à : [résolu] Besoin d'aide pour écrire une requête SQL compliquée


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