Requête SQL bloquante

kirato Messages postés 2 Statut Membre -  
kirato Messages postés 2 Statut Membre -
Bonsoir à tous ! Avant toute chose : bonne année 2007 ! :) Espérons qu'elle soit pleine de surprises et que j'ai plus de problèmes avec mysql >_<

Pour en venir à mon problème, j'ai une requête SQL assez lourde (elle porte sur des tables déjà bien remplies ^^), qui mêle jointures et requêtes imbriquées. Mon soucis étant qu'elle est tellement conséquente qu'elle me sature complètement ma connexion à la base, et me bloque donc le serveur mysql (du moins pour le login que j'utilise).
Je me demandais donc si des esprits avisés pouvaient m'aider sur ce coup, ça fait 2 soirées que je m'arrache les cheveux dessus -_-

Bon je vous met la requête en question (c'est moche désolé) :

SELECT DISTINCT p1.id_produit, p1.reference, p1.date_parution
FROM ab.produit p1
LEFT OUTER JOIN ab.piste p ON p.id_produit = p1.id_produit
WHERE p.num_support != -1
AND p1.id_produit NOT IN
  (SELECT DISTINCT s.code_barre
  FROM ab_scpp.scpp_support s
  INNER JOIN ab_scpp.scpp_lien_support sls ON sls.code_barre=s.code_barre
  GROUP BY s.code_barre, nb_support
  HAVING COUNT(DISTINCT num_support) = nb_support 
OR nb_support IS NULL )
AND p1.id_label NOT IN
  (SELECT m.id_label FROM ab_scpp.scpp_marque m
  INNER JOIN ab_scpp.fournisseurs f ON f.id_fournisseur=m.id_fournisseur
  WHERE f.mandat='N')
LIMIT 10 OFFSET 0


Avec le limit à 10 la requête passe ... dès que j'augmente aux alentours de 100 la requête commence à mettre 30s à s'exécuter :/ Je vous livre le EXPLAIN avec :

id 	select_type 	        table 	type            possible_keys 	key 	      key_len   ref 	                rows 	Extra

1 	PRIMARY 	        p 	index 	        NULL 	        PRIMARY 	15 	NULL 	                57024 	Using where; Using index; Using temporary

1 	PRIMARY 	        p1 	eq_ref 	        PRIMARY 	PRIMARY 	13 	ab.p.id_produit           1 	Using where

3 	DEPENDENT SUBQUERY 	m 	ref_or_null 	index_label 	index_label 	 3 	func                      4 	Using where

3 	DEPENDENT SUBQUERY 	f 	eq_ref         	PRIMARY 	PRIMARY 	 4 	ab_scpp.m.id_fournisseur  1 	Using where

2 	DEPENDENT SUBQUERY 	sls 	index 	        PRIMARY 	PRIMARY 	19 	NULL 	                47150 	Using index; Using temporary; Using filesort

2 	DEPENDENT SUBQUERY 	s 	eq_ref 	        PRIMARY 	PRIMARY 	13 	ab_scpp.sls.code_barre 	  1


Comme vous le voyez, c'est la sous-requête comportant un GROUP BY qui fait très mal ... ma question serait de savoir s'il est possible d'améliorer la requête ou si je dois me contenter de faire un traitement php sur les données récupérées de 2 requêtes sql bien séparées ?

Si vous avez besoin d'autres précisions il ne faut pas hésiter à me demander ! (pour info je tourne sur du mysql 5.0.27)

Merci beaucoup d'avance pour votre aide :)

2 réponses

Jean-François Pillou Messages postés 19261 Date d'inscription   Statut Webmaster Dernière intervention   63 279
 
Le mieux est de repenser les index...

Sinon tu peux aussi tenter de réorganiser tes tables. Par exemple pour ab_scpp.scpp_support :
ALTER TABLE `ab_scpp.scpp_support` ORDER BY `code_barre` ASC


Enfin, reste la possibilité d'utiliser des vues !
0
kirato Messages postés 2 Statut Membre
 
Merci pour ton intérêt Jeff :) Finalement j'ai remané ma requête pour utiliser une table temporaire sur la sous-requête posant problème .. C'est pas très élégant mais au final ça donne ça :

SELECT DISTINCT p1.id_produit, p1.reference, p1.date_parution
FROM abeille.produit p1
LEFT OUTER JOIN abeille.piste p ON p.id_produit = p1.id_produit
LEFT OUTER JOIN
  (SELECT DISTINCT s.code_barre
  FROM abeille_scpp.scpp_support s
  INNER JOIN abeille_scpp.scpp_lien_support sls ON sls.code_barre=s.code_barre
  GROUP BY s.code_barre, nb_support
  HAVING COUNT(DISTINCT num_support) = nb_support OR nb_support IS NULL)
  AS tempo
  ON p1.id_produit = tempo.code_barre
WHERE tempo.code_barre IS NULL
AND p.num_support != -1
AND p1.id_label NOT IN
  (SELECT m.id_label FROM abeille_scpp.scpp_marque m
  INNER JOIN abeille_scpp.fournisseurs f ON f.id_fournisseur=m.id_fournisseur
  WHERE f.mandat='N')


Finalement au lieu de mettre un temps infini pour s'exécuter, j'obtiens le résultat en environ 50s. Vu ce que ça donnait avant c'est beaucoup mieux :p Je vais tester un traitement php pour voir si c'est plus rapide !
0