Surcharge BDD ?

WRInaute passionné
Bonjour,

Je trouvais que le back office était un peu lent et j'ai fait un diagnostic à base de microtime pour savoir d'où cela venait. Il s'avère que si je mets un marqueur juste avant et juste après la requête, il m'indique plus de 6 secondes... Il ne met pas autant pour faire les autres requêtes du site. Il est vrai que cette requête-ci est particulièrement longue (référencement des 20 dernières commandes, couplées avec les tables de factures, et deux autres tables pour des informations sur les commandes.

Voici les marqueurs :

Code:
$time_start = microtime_float();
		$les_demandes = $BDD_connexion->get($req_les_demandes);
		$demandes = array();
$time_end = microtime_float();

la fonction get dans ma classe :
Code:
	function get($q){	
		$to_return = FALSE;
		if($this->link==0 && $this->host!="" && $this->username!="" && $this->dbname) $this->open($this->dbname);
		if($this->link!=0){ //echo $q."<br />";
			
			$resultset = @mysql_query($q) or print("
<h2>Une erreur SQL est survenue</h2>
<strong>Erreur N° : </strong>".mysql_errno()."
<br /><strong>Description : </strong>".mysql_error()."
<br /><strong>Host / User / DB :</strong> ".$this->host." / ".$this->username." / ".$this->dbname."
<br /><strong>Req posant problème :</strong> ".$q."
<br /><strong>Link :</strong> ".$this->link.""
);
			if($resultset){
				$this->nb_query++;
				$this->last_query = $q;
				if(mysql_num_rows($resultset)==0) $to_return = 0;
				else $to_return = $resultset;
			}
		}
		return $to_return;
	}

Temps d'exécution : 6.24645709991...

D'où cela peut-il venir ?

Merci d'avance pour votre aide.

[EDIT]J'ajoute que je viens d'imprimer ma requête et de la faire exécuter à partir de phpMyAdmin, la durée d'exé semble être la même "Affichage des enregistrements 0 - 19 (20 total, traitement: 6.4335 sec.)"[/EDIT]
 
WRInaute passionné
ltressens a dit:
Ca vient de tout ce que tu nous montre pas ici :
structure de la table et requete utilisée...
oui c'est sûr vue que ça le fait aussi sur phpmyadmin.. alors ya un gros select de 45 champs, 4 left join pour 20 résultats... c'est méchant 4 left join ?
 
WRInaute impliqué
tente un explain dans phpmyadmin ou en ligne de commande pour voir ce que fait mysql, ajoute des index en conséquence, et pour les jointures utilisent des requêtes imbriqués plutot que des jointures ca améliore pas mal les choses...
 
WRInaute impliqué
Je ne sais pas exactement ce que tu recupères mais si ta requete est mal faite elle peut renvoyer une tres grande quantité de lignes. J'ai deja eu ce problème il a été reglé en optimisant ma requete et en utilisant au maximum DISTINCT
 
WRInaute passionné
skippyzrnr a dit:
Je ne sais pas exactement ce que tu recupères mais si ta requete est mal faite elle peut renvoyer une tres grande quantité de lignes. J'ai deja eu ce problème il a été reglé en optimisant ma requete et en utilisant au maximum DISTINCT
ben non, elle renvoie 20 lignes puisque je l'ai limitée.. et en l'occurrence, toutes les informations sont importantes puisqu'il s'agit de commandes, et donc toutes uniques.
 
WRInaute passionné
julienr a dit:
tente un explain dans phpmyadmin ou en ligne de commande pour voir ce que fait mysql, ajoute des index en conséquence, et pour les jointures utilisent des requêtes imbriqués plutot que des jointures ca améliore pas mal les choses...

Voici ce que dit le "explain" :

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE D ALL NULL NULL NULL NULL 5234 Using where; Using temporary; Using filesort
1 SIMPLE PC ALL NULL NULL NULL NULL 69
1 SIMPLE C eq_ref PRIMARY PRIMARY 4 qgcom2.D.centre 1
1 SIMPLE F4 ALL NULL NULL NULL NULL 1050
 
WRInaute impliqué
Code:
Using filesort
si tu as un order dans ta requete c'est possible que ce soit lui qui bouffe tout
surtout si tu as beaucoup de ligne dans le tri car le limit n'agit que sur le résultat trié
-> positionne un index sur ta colonne de tri
 
WRInaute passionné
julienr a dit:
Code:
Using filesort
si tu as un order dans ta requete c'est possible que ce soit lui qui bouffe tout
surtout si tu as beaucoup de ligne dans le tri car le limit n'agit que sur le résultat trié
-> positionne un index sur ta colonne de tri

Je crois que l'on approche du pb et donc de la solution (bien amené jusque là ;)) la définition de l'index a permis d'accélérer largement la requete "SELECT * FROM table ORDER BY date DESC"

Sur ma longue requête, si j'enlève le ORDER BY, ça s'accèlère très largement.

Mais AVEC l'index ET le ORDER BY, ça rame encore... ?

Merci de votre aide..
 
WRInaute impliqué
les index accelèrent les choses si tu as une cardinalité élevée, c'est à dire le nombre de valeurs différentes que tu as dans ta colonne...
c'est à dire combien maintenant avec l'index et combien sans le order ?
 
WRInaute passionné
julienr a dit:
les index accelèrent les choses si tu as une cardinalité élevée, c'est à dire le nombre de valeurs différentes que tu as dans ta colonne...
c'est à dire combien maintenant avec l'index et combien sans le order ?
avec order calculé via phpmyadmin avec ma grosse requete : 7.45 sec
sans : 0.0257 sec

si c'est pas fou ça...
 
WRInaute discret
bein si tu as que 20 résultats : pas de order, tu rentres tout dans un tableau et tu tries le tableau en post traitement.

Sinon pou info les index servent pour tous les champs dans un where, un order ou tout autre champs qui sert à limiter le nombre de lignes
 
WRInaute passionné
guicher a dit:
elle fait combien de Mo ta base ?

ça je sais pas. ça me parait énorme de prendre tout dans un tableau, de faire le tri ensuite (5500 x 45 champs) en array_reverse puis de ne récupérer que les 20 premiers résultats (comment on fait d'ailleurs sur un tableau sans faire une for ?)

on peut faire autrement ? on peut pas dire que l'index de la table se fait automatiquement sur les dates décroissantes ?

merci encore
 
WRInaute impliqué
tu peux essayer de demander à mysql d'ordonner physiquement tes lignes sur ta colonne date, mais je ne sais pas ce que cela vaut
 
WRInaute passionné
FlorentP a dit:
C'est quoi la requete et la structure des tables ?

ça tu l'auras deviné, c'est très confidentiel. Je suis désolé j'ai donné le maximum d'informations mais tout le monde n'a pas à savoir ce qui se trouve comme informations dans notre base de commandes.. si tu as des questions plus précises, je pourrai certainement te répondre.. :oops:
 
WRInaute discret
Si tu ne veux pas donner la vrai structure et la requete, modifie les noms et supprime tout ce qui ne sert à rien. Le but étant se savoir :
- où se trouvent tes index
- sur quels champs tu fais tes jointures

Parceque là clairement d'après ton explain, ya des gros soucis, ya une seul index utilisé sur 4 endroits où tu pourrait utilisé donc forcément c'est violent.

Sans ça, on peut pas t'aider, on peut juste te rediriger vers des cours sur mysql, tu trouvera ça facilement sur google
 
WRInaute discret
RomsIW a dit:
julienr a dit:
tu peux essayer de demander à mysql d'ordonner physiquement tes lignes sur ta colonne date, mais je ne sais pas ce que cela vaut
comment fait-on ça ?
S'pas ça qui va optimiser tes jointures, ça ça peut servir pour économiser des balades inutiles de la tête de lecture sur le disque dûr, c'est un peu le dernier niveau d'optimisation, t'es encore loin de ça tant que t'as pas peaufiné tes jointures :p
 
WRInaute passionné
FlorentP a dit:
Si tu ne veux pas donner la vrai structure et la requete, modifie les noms et supprime tout ce qui ne sert à rien. Le but étant se savoir :
- où se trouvent tes index
- sur quels champs tu fais tes jointures

Parceque là clairement d'après ton explain, ya des gros soucis, ya une seul index utilisé sur 4 endroits où tu pourrait utilisé donc forcément c'est violent.

Sans ça, on peut pas t'aider, on peut juste te rediriger vers des cours sur mysql, tu trouvera ça facilement sur google

ok voici ce que je peux dire :

Code:
SELECT D.*, C.lettre, C.libelle, C.couleur, PC.tarif, F1.num AS num_facture_type1 
FROM TABLE_COMMANDES AS D 

LEFT JOIN TABLE_REL_PRODUITS_PAR_CENTRES AS PC ON PC.id_centre=D.id_centre AND PC.id_produit=D.type_saut 
LEFT JOIN TABLE_CENTRES AS C ON C.id_centre=D.id_centre 
LEFT JOIN TABLE_FACTURES AS F1 ON F1.id_cmd=D.id_cmd 

WHERE D.etat<>'-1' ORDER BY D.date DESC LIMIT 0,20

à propos des index :

Code:
PRIMARY 5249   id
INDEX 	5249 date
 
WRInaute discret
TABLE_CENTRES => il faut un index simple sur "id_centre" (même une primary key serait logique, y'en a pas déjà ?)
TABLE_FACTURES => idem sur "id_cmd"

TABLE_REL_PRODUITS_PAR_CENTRES => il faut un index composé, sur "id_centre, id_produit"
(ou "id_produit, id_centre" selon comment tu veux que cet index puisse resservir)

TABLE_COMMANDES => if faut un index sur "etat, date"
 
WRInaute passionné
FlorentP a dit:
TABLE_CENTRES => il faut un index simple sur "id_centre" (même une primary key serait logique, y'en a pas déjà ?)
TABLE_FACTURES => idem sur "id_cmd"

TABLE_REL_PRODUITS_PAR_CENTRES => il faut un index composé, sur "id_centre, id_produit"
(ou "id_produit, id_centre" selon comment tu veux que cet index puisse resservir)

TABLE_COMMANDES => if faut un index sur "etat, date"
TABLE_CENTRES il y a la PK évidemment
TABLE_FACTURES idem
TABLE_REL... comment fait on un index composé ?
TABLE_COMMANDES comment fait on un index sur "etat, date" ?

Pour le D.*, c'était pour raccourcir car il y a pas mal de champs sélectionnés et qu'il n'y a pas de champs intéressant à citer ici ;)

merci encore
 
WRInaute discret
C'est bizarre que tu dises qu'il y a une PK sur le champs parce que ton explain indique que la jointure n'utilise pas d'index :

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE D ALL NULL NULL NULL NULL 5234 Using where; Using temporary; Using filesort
1 SIMPLE PC ALL NULL NULL NULL NULL 69
1 SIMPLE C eq_ref PRIMARY PRIMARY 4 qgcom2.D.centre 1
1 SIMPLE F4 ALL NULL NULL NULL NULL 1050

=> Sur la table "C" il y a bien un index, nikel, le type est "eq_ref"
=> pour F4 par contre, le type est "ALL", c'est à dire qu'il n'y pas d'index, mysql scan toute le contenu de la table dans le disque dur => très lourd

Pour l'index simple :
ALTER TABLE t ADD INDEX (c)
Pour un index composé :
ALTER TABLE t ADD INDEX (c1,c2)
 
WRInaute passionné
FlorentP a dit:
C'est bizarre que tu dises qu'il y a une PK sur le champs parce que ton explain indique que la jointure n'utilise pas d'index :

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE D ALL NULL NULL NULL NULL 5234 Using where; Using temporary; Using filesort
1 SIMPLE PC ALL NULL NULL NULL NULL 69
1 SIMPLE C eq_ref PRIMARY PRIMARY 4 qgcom2.D.centre 1
1 SIMPLE F4 ALL NULL NULL NULL NULL 1050

=> Sur la table "C" il y a bien un index, nikel, le type est "eq_ref"
=> pour F4 par contre, le type est "ALL", c'est à dire qu'il n'y pas d'index, mysql scan toute le contenu de la table dans le disque dur => très lourd

Pour l'index simple :
ALTER TABLE t ADD INDEX (c)
Pour un index composé :
ALTER TABLE t ADD INDEX (c1,c2)

J'ai réglé le pb de façon très simple :

j'ai limité la recherche à un certain nombre de résultats : "recherche parmi les X dernières commande (LAST_INSERT_ID - X)" et c'est devenu très rapide d'un coup :)

Merci !
 
Discussions similaires
Haut