[SQL] Temps d'execution d'une requete bizarre

Temps d'execution d'une requete bizarre [SQL] - SQL/NoSQL - Programmation

Marsh Posté le 18-07-2003 à 12:18:07    

Alors voila ma requete  

Code :
  1. SELECT
  2.   COUNT(v.log_id) as nbconnexion,
  3.   w.lb_utilisateur,
  4.   MAX(v.log_date) as dates
  5. FROM
  6.   v_mca_log_gold v,
  7.   vwcr_utilisateur w,
  8.   v_mca_securite s
  9. WHERE
  10.   s.cd_reseau in ('NGR1') and
  11.   upper(v.log_login) = upper (w.lb_login_nt) and
  12.   upper(v.log_login) = upper (s.login_nt)
  13. group by w.lb_utilisateur order by w.lb_utilisateur


 
Cette requete met 8 min 45 à s'exécuter  
 
alors que la requete suivante  
 

Code :
  1. SELECT
  2.   COUNT(v.log_id) as nbconnexion,
  3.   w.lb_utilisateur,
  4.   MAX(v.log_date) as dates
  5. FROM
  6.   v_mca_log_gold v,
  7.   vwcr_utilisateur w,
  8.   v_mca_securite s
  9. WHERE
  10.   upper(v.log_login) = upper (w.lb_login_nt) and
  11.   upper(v.log_login) = upper (s.login_nt)
  12. group by w.lb_utilisateur order by w.lb_utilisateur


 
Alors que cette requete met juste 2 secondes à s'exécuter
j'ai juste enlever la condition :

Code :
  1. s.cd_reseau in ('NGR1')

 
 
 
Quelqu'un a une idée pour améliorer le temps de réponse pour la première requete ??


Message édité par -bigfoot- le 18-07-2003 à 12:19:40
Reply

Marsh Posté le 18-07-2003 à 12:18:07   

Reply

Marsh Posté le 18-07-2003 à 12:23:39    

essaye s.cd_reseau = 'NGR1'
 
puisqu il n y a qu un élément
ca vient peut etre aussi d une table avec bcp bcp d'enregistrement et pas d index sur ton champ (mais avec un tps pareil je doute que ce soit ca qd meme...)

Reply

Marsh Posté le 18-07-2003 à 12:31:14    

sinon y a pas le mot cle "like"?

Reply

Marsh Posté le 18-07-2003 à 12:43:36    

Ma requete initial est sur plusieurs réseaux donc j'ai un "in"  
Mais sinon j'ai essayé avec un "=" avec un seul réseau et j'ai le même temps de réponse
 
Quand même bizarre ce problème  :pfff:  
sinon si ca se peut vous aider, le SGBD est Oracle


Message édité par -bigfoot- le 18-07-2003 à 12:44:26
Reply

Marsh Posté le 18-07-2003 à 12:59:30    

:hello: explain plan est ton ami

Reply

Marsh Posté le 18-07-2003 à 13:03:24    

-BigFoot- a écrit :

Ma requete initial est sur plusieurs réseaux donc j'ai un "in"  
Mais sinon j'ai essayé avec un "=" avec un seul réseau et j'ai le même temps de réponse
 
Quand même bizarre ce problème  :pfff:  
sinon si ca se peut vous aider, le SGBD est Oracle


Sans doute qu'il n'y pas d'index sur ta colonne CD_RESEAU.
Essaie en créant un index sur les deux champs login_nt et cd_reseau de la table v_mcs_securite.
Si ca marche pas mieux je vois pas ...
Y a combien d'enregistrement dans tes tables ? T'as essayé de faire un explain plan pour voir si t'as pas un access full sur une grosse table ?


---------------
Gérez votre collection de BD en ligne ! ---- Electro-jazzy song ---- Dazie Mae - jazzy/bluesy/cabaret et plus si affinité
Reply

Marsh Posté le 18-07-2003 à 13:32:09    

Merci à tous pour vos réponses   :)  
 
Je vais essayer le explain plan (je ne sais pas comment l'utiliser mais je vais faire une petite recherche) et je vous tiens au courant  ;)

Reply

Marsh Posté le 18-07-2003 à 15:56:15    

Bon j'ai réussi à faire un explain plan mais maintenant j'ai besoin d'expert pour m'aider à le décrypter et savoir ce qu'il faut que je fasse pour optimiser mon code
 
En tout les cas, il est vraiment excellent ce forum, on a toujours de l'aide  :love:  :love:  
 
Bon voila l'image de ce que j'ai :  
 
http://bigtoof.free.fr/explain.jpg
 
 
Merci d'avance

Reply

Marsh Posté le 18-07-2003 à 16:18:00    

-BigFoot- a écrit :

Bon j'ai réussi à faire un explain plan mais maintenant j'ai besoin d'expert pour m'aider à le décrypter et savoir ce qu'il faut que je fasse pour optimiser mon code
 
En tout les cas, il est vraiment excellent ce forum, on a toujours de l'aide  :love:  :love:  
 
Bon voila l'image de ce que j'ai :  
 
http://bigtoof.free.fr/explain.jpg
 
 
Merci d'avance


Vu qu'il semble à l'image de ton post que tu utilise TOAD, le mieux est de l'utiliser !
Tu tape ta requete et tu fait CTRL+E et zou !
Enfin presque, faut juste définir la table d'explian plan dans les options. Donc dans le menu de TOAD : view>option> puis tu choisi Oracle et tu met le nom de ta table d'explain plan dans le bon champ ( certainement PLAN_TABLE ou un truc comme ça ).
Voilà.
Tu peux aussi regarder là : http://bai.skreel.org/?categorie=ora&offset=25


---------------
Gérez votre collection de BD en ligne ! ---- Electro-jazzy song ---- Dazie Mae - jazzy/bluesy/cabaret et plus si affinité
Reply

Marsh Posté le 18-07-2003 à 16:35:34    

oki merci pour l'info  :D  
sinon tu vois ce que je dois optimiser ?
 
Je vais essayer de créer un index sur le champ cd_reseau

Reply

Marsh Posté le 18-07-2003 à 16:35:34   

Reply

Marsh Posté le 18-07-2003 à 20:28:08    

Poste les indexes de tes tables s'il te plait.
 
A tout les coups, s.cd_reseau n'est pas correctement indexé, et le mettre dans la requête provoque un nested loop sur un index contenant plus de champs que ceux filtrés.

Reply

Marsh Posté le 18-07-2003 à 20:33:24    

Sinon, réécrit la requête comme suit :
 

SELECT  
 COUNT(v.log_id) as nbconnexion,  
 w.lb_utilisateur,  
 MAX(v.log_date) as dates  
FROM  
 vwcr_utilisateur w,  
 v_mca_securite s,  
 v_mca_log_gold v  
WHERE  
 upper(s.login_nt) = upper (w.lb_login_nt) and    
 s.cd_reseau in ('NGR1') and
 upper(v.log_login) = upper (w.lb_login_nt)
group by w.lb_utilisateur order by w.lb_utilisateur


 
PS: j'ai rien changé au niveau de la requête, j'ai juste réarangé les champs pour qu'Oracle s'en sorte mieu au niveau des jointures (il va éviter de faire des doublons qu'ils faut ensuite filtrer) en réarangeant à la fois l'ordre des requêtes et en utilisant w.lb_login_nt pour les deux jointures, puisqu'à la base, je suppose que c'est un index unique, alors que s.login_nt semble contenir des doublons.


Message édité par MagicBuzz le 18-07-2003 à 20:39:07
Reply

Marsh Posté le 18-07-2003 à 20:35:10    

Je poste cela lundi car la je ne suis plus au taff  :D

Reply

Marsh Posté le 18-07-2003 à 20:37:54    

sorry, j'étais très occupé aujourd'hui :)
 
en fait, la modif sur la jointure devrait te faire gagner pas mal : tu devrais remplacer la série "sort, filter, nested loop hash join" par un "inner join" qui sera énormément plus rapide
ça devrais aussi te virer le "union-all"
 
sinon, vérifie que tes index uniques style "login" sont bien triés, à moins qu'ils soient souvent mis à jour.


Message édité par MagicBuzz le 18-07-2003 à 20:40:14
Reply

Marsh Posté le 21-07-2003 à 09:13:47    

Merci beaucoup MagicBuzz ;) , en utilisant ta requête dans le sens que tu m'as dis je passe de 8 min 45 sec à 2 sec.
Faudrait à l'avenir que je sache bien interpréter le résultat d'un explain

Reply

Marsh Posté le 21-07-2003 à 11:32:38    

Bah putain ! Ca c'est de l'optimisation :D
 
Même pas fait exprès, je pensais gagner seulement entre 20 et 30% :)

Reply

Marsh Posté le 21-07-2003 à 12:36:06    

C'est un record d'optimisation  :D

Reply

Marsh Posté le 21-07-2003 à 14:08:28    

Sinon, avant même d'interpréter le résultat de l'explain, il faut modéliser dans sa tête la base et la requête.
 
Grossomodo :
-> Faire les filtres les filtres et les jointures regroupés table par table.
-> Toujours faire les jointures avant les filtres (sauf pour la première, qui n'est pas fille d'une jointure)
-> Pour les jointures, réutiliser les tables qui contiennent le moins de données possibles, même si au niveau du modèle ça ne correspond pas aux relations qu'on a fait.
 
Exemple :
 
PROPRIETAIRE
----
UID
NOM
PRENOM
PERMIS_ID
 
 
ADRESSE
------
AID
NUMERO
RUE
VILLE
CP
PAYS
TYPE
PROPRIETAIRE_ID
 
VOITURE
-------
IMMATRICULATION
PROPRIETAIRE_ID
 
Maintenant, le problème est :
 
Retrouver l'adresse de résidence principaledu conducteur de la voiture immatriculée 1234AB56 (histoire de lui envoyer un PV par exemple)
 
Tu commences par le filtre le plus restrictif, donc ici, l'imatriculation, puisque c'est un identifiant (une ligne retournée)
 
where v.immatriculation = '1234AB56'
 
Ensuite, tu ne vas pas t'amuser à lier les utilisateurs aux adresses, sinon tu vas te retrouver avec un nombre incalculable de lignes - autant qu'il y a d'adresse dans la base -, qui devront être filtrées au moment de la jointure (perte de temps).  
 
Donc tu commences par retrouver le conducteur.
 
and p.uid = v.proprietaire_id
 
Puis, tu vas chercher les adresses du conducteur (NON, ne fait pas le filtre sur le type d'adresse AVANT, sinon tu vas filtrer les adresses habitation de TOUS les propriétaires. Donc à nouveau, trop de lignes. Tu vas donc chercher la liste des adresses du conducteur, qui représentent beaucoup moins de lignes.
 
and a.PROPRIETAIRE_ID = u.UID
 
Et enfin (et seulement maintenant) tu vas filtrer le type d'adresse.
 
and a.type = 'PRINCIPALE'
 
Ensuite, dans le FROM, il faut mettre les tables dans l'ordre inverse de leur position dans la requête.
 
Truc à bien garder en tête aussi :
 
and a.PROPRIETAIRE_ID = u.UID
 
est différent de  
 
and u.UID = a.PROPRIETAIRE_ID
 
En effet, le second va recherche tous les UID qui sont présents dans les adresses, et ensuite va filter pour retrouver les UID qui connerspondent aux précédents critères. Alors que le premier va rechercher les adresses qui correspondent uniquement aux prorpiétaires déjà filtrés.
 
Le requête est donc :
 
SELECT p.NOM, p.PRENOM, a.NUMERO, a.RUE, a.CP, a.VILLE, a.PAYS
FROM adresse a, proprietaire p, voiture v
WHERE v.immatriculation = '1234AB56'
AND p.uid = v.proprietaire_id
AND a.PROPRIETAIRE_ID = u.UID
AND a.type = 'PRINCIPALE'
 
Et non pas un truc monstrueux genre :
 
SELECT p.NOM, p.PRENOM, a.NUMERO, a.RUE, a.CP, a.VILLE, a.PAYS
FROM proprietaire p, voiture v, adresse a
WHERE a.PROPRIETAIRE_ID = v.PROPRIETAIRE_ID
AND a.PROPRIETAIRE = p.UID
AND a.TYPE = 'PRINCIPALE'
and v.IMMATRICULATION = '1234AB56'
 
La seconde est tout ce qu'il y a de plus immonde :D
... mais elle fonctionne aussi (c'est bien ça le problème...)


Message édité par MagicBuzz le 21-07-2003 à 14:12:11
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed