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

  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  optimisation requête mysql

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

optimisation requête mysql

n°2254718
networkinf​o
Posté le 01-04-2015 à 15:33:17  profilanswer
 

Bonjour
 
Ma requête sur 20000 enregistrements prends 20s

Code :
  1. SELECT p.id_produit,
  2.                     p.nom_produit,
  3.                     p.id_modele,
  4.                     p.description_produit,
  5.                     p.ref_produit,
  6.                     p.id_cat,
  7.                     p.stock_produit,
  8.                     p.actif,
  9.                     p.new,
  10.                     p.prix_vente_produit,
  11.                     p.prix_promo,
  12.                     p.coupdecoeur,
  13.                                                            
  14.                     m.id_modele,
  15.                     m.nom_modele,
  16.                     m.id_marque,
  17.                    
  18.                     ma.nom_marque,
  19.                     ma.id_marque,
  20.                     c.nom_cat
  21.                    
  22.                     FROM tb_produits p
  23.                     LEFT JOIN tb_modeles m
  24.                     ON p.id_modele = m.id_modele
  25.                    
  26.                     LEFT JOIN tb_marques ma
  27.                     ON ma.id_marque = m.id_marque
  28.                    
  29.                     LEFT JOIN tb_cat c
  30.                     ON c.id_cat = p.id_cat


 
Je stocke les résultats dans un tableau php et ajoute une pagination mais je n'ai pas l'impression que ça vienne de la

Code :
  1. $nombreDePages  = ceil($nb_resultats / $nombreDeResultatsParPage);
  2. if (isset($_GET['page']))
  3. {
  4.     $page = intval($_GET['page']); // On récupère le numéro de la page indiqué dans l'adresse (livreor.php?page=4)
  5. }
  6. else // La variable n'existe pas, c'est la première fois qu'on charge la page
  7. {
  8.     $page = 1; // On se met sur la page 1 (par défaut)
  9. }
  10. //On calcule le numéro du premier message qu'on prend pour le LIMIT de MySQL
  11. $premierResultatAafficher = ($page - 1) * $nombreDeResultatsParPage;
  12. $query .=  ' ORDER BY id_produit ASC LIMIT ' . $premierResultatAafficher . ', ' . $nombreDeResultatsParPage;
  13. $result = mysql_query($query) or die($query . " - " . mysql_error());
  14. while($data = mysql_fetch_object($result)){
  15.     $id_produit[$i]  = $data->id_produit;
  16.     $description_produit[$i] = trim($data->description_produit);
  17.     $nom_produit[$i] = $data->nom_produit;
  18.     $nom_cat[$i] = $data->nom_cat;
  19.     $ref_produit[$i] = $data->ref_produit;
  20.     $prix_vente_produit[$i] = $data->prix_vente_produit;
  21.     $prix_promo[$i] = $data->prix_promo;
  22.     $nom_marque[$i] = $data->nom_marque;
  23.     $nom_modele[$i] = $data->nom_modele;
  24.     $stock_produit[$i] = $data->stock_produit;
  25.     $actif[$i] = $data->actif;
  26.     $new[$i] = $data->new;
  27.     $coupdecoeur[$i] = $data->coupdecoeur;
  28.    
  29.   $i++;
  30. }


 
Je pense plus tôt que c'est une question d'index mais je sèche , j'ai essayé qq trucs mais sans résultats
D'ailleurs la requête suivante est rapide  

Code :
  1. $query = 'SELECT p.id_produit,
  2.                     p.nom_produit,
  3.                     p.id_modele,
  4.                     p.description_produit,
  5.                     p.ref_produit,
  6.                     p.id_cat,
  7.                     p.stock_produit,
  8.                     p.actif,
  9.                     p.new,
  10.                     p.prix_vente_produit,
  11.                     p.prix_promo,
  12.                     p.coupdecoeur,
  13.                                                            
  14.                     m.id_modele,
  15.                     m.nom_modele,
  16.                     m.id_marque,
  17.                    
  18.                     ma.nom_marque,
  19.                     ma.id_marque,
  20.                     c.nom_cat
  21.                    
  22.                     FROM tb_produits p
  23.                     LEFT JOIN tb_modeles m
  24.                     ON p.id_modele = m.id_modele
  25.                    
  26.                     LEFT JOIN tb_marques ma
  27.                     ON ma.id_marque = m.id_marque
  28.                    
  29.                     LEFT JOIN tb_cat c
  30.                     ON c.id_cat = p.id_cat
  31.                    
  32.                    
  33.                    
  34.                     WHERE ( m.nom_modele LIKE "%'.$mot_cle.'%"
  35.                                                 OR nom_produit LIKE "%'.$mot_cle.'%"
  36.                                                 OR p.ref_produit LIKE "%'.$mot_cle.'%"
  37.                                                  )
  38.                                                
  39.                                                
  40.                     ' ;


 
Merci à ceux qui prendront le temps de me répondre :)

mood
Publicité
Posté le 01-04-2015 à 15:33:17  profilanswer
 

n°2254720
rufo
Pas me confondre avec Lycos!
Posté le 01-04-2015 à 15:46:05  profilanswer
 

Utilise EXPLAIN dans phpMyAdmin pour voir ce qui bloque :
EXPLAIN SELECT.... FROM...
 
Après, le OR et le like, ça te tue les perfs. En général, avec LIKE, impossible d'utiliser un index. Déjà, pour virer les OR, tu peux faire ça :
'SELECT...FROM...WHERE CONCAT(m.nom_modele, nom_produit, p.ref_produit) LIKE "%'.$mot_cle.'%"';   ;)


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
n°2254737
networkinf​o
Posté le 01-04-2015 à 16:43:46  profilanswer
 

Merci pour l'astuce je ne connaissais pas !
Mais cette dernière requête mets 2s justement, c'est la 1ère en haut qui met 20s !

n°2254741
rufo
Pas me confondre avec Lycos!
Posté le 01-04-2015 à 16:50:59  profilanswer
 

p.id_modele, m.id_modele, ma.id_marque, m.id_marque, c.id_cat, p.id_cat sont tous déclarés clé primaire ou clé étrangère (suivant le cas) ?
 
Ca donne quoi explain ?
 
Parce que je suis étonné des perfs : mon appli Astres a une requête sur les tickets qui fait des LEFT JOIN sur bien 6-7 tables dont une fait plus de 30000 enregistrements et ça met pas 20s. Ton appli tourne sur quel matos ? Moi, c'est un CPU 2.5 Ghz double coeur, 2 Go de ram.
 
Tu peux aussi tuner le fichier de conf de Mysql pour augmenter la taille de certains caches, buffers, nb de tables temporaires ouvertes en même temps ou taille des tables temporaires en mémoire ou sur le hdd...
 


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
n°2254774
networkinf​o
Posté le 01-04-2015 à 23:37:39  profilanswer
 

toutes déclarées en primaire dans leur tables respectives, pas de clé étrangères car MySam
 
 
Voilà le explain
 
EXPLAIN  SELECT p.id_produit, p.nom_produit, p.id_modele, p.description_produit, p.ref_produit, p.id_cat, p.stock_produit, p.actif, p.new, p.prix_vente_produit, p.prix_promo, p.coupdecoeur, m.id_modele, m.nom_modele, m.id_marque, ma.nom_marque, ma.id_marque, c.nom_cat
FROM tb_produits p
LEFT  JOIN tb_modeles m ON p.id_modele = m.id_modele
LEFT  JOIN tb_marques ma ON ma.id_marque = m.id_marque
LEFT  JOIN tb_cat c ON c.id_cat = p.id_cat
ORDER  BY id_produit
 
 
id     select_type     table     type     possible_keys     key     key_len     ref     rows     Extra
1     SIMPLE     p     ALL     NULL     NULL     NULL     NULL     20321     Using filesort
1     SIMPLE     m     eq_ref     PRIMARY     PRIMARY     4     transforbike.p.id_modele     1      
1     SIMPLE     ma     eq_ref     PRIMARY     PRIMARY     4     transforbike.m.id_marque     1      
1     SIMPLE     c     eq_ref     PRIMARY     PRIMARY     4     transforbike.p.id_cat     1
 
 
J'ai juste fait un coup de mysqltuner pour le my.conf
3Go de mémoire, CPU 2Ghz
 
Sur quoi dois-je faire les index ?


Message édité par networkinfo le 01-04-2015 à 23:49:43
n°2254775
networkinf​o
Posté le 02-04-2015 à 00:06:21  profilanswer
 

c'est résolu
 
Le pb vient de mon php car je calcule le nombre total de réponse sur la même requête, je la fais donc 2 fois
 
J'ai aussi ajouté un mysql_free_result avant de faire la vrai requête
merci !

n°2254785
rufo
Pas me confondre avec Lycos!
Posté le 02-04-2015 à 10:17:28  profilanswer
 

Pour les clés étrangères, mets un index sur ces champs. ;)


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
n°2254812
networkinf​o
Posté le 02-04-2015 à 14:05:41  profilanswer
 

Merci :)

 

Et faire ça

Code :
  1. $result = mysql_query($query) or die($query . " - " . mysql_error());
  2. while($data = mysql_fetch_object($result)){
  3.     $id_produit[$i]  = $data->id_produit;
  4.     $description_produit[$i] = trim($data->description_produit);
  5.     $nom_produit[$i] = $data->nom_produit;
  6.     $nom_cat[$i] = $data->nom_cat;
  7.     $ref_produit[$i] = $data->ref_produit;
  8.     $prix_vente_produit[$i] = $data->prix_vente_produit;
  9.     $prix_promo[$i] = $data->prix_promo;
  10.     $nom_marque[$i] = $data->nom_marque;
  11.     $nom_modele[$i] = $data->nom_modele;
  12.     $stock_produit[$i] = $data->stock_produit;
  13.     $actif[$i] = $data->actif;
  14.     $new[$i] = $data->new;
  15.     $coupdecoeur[$i] = $data->coupdecoeur;
  16.  
  17.   $i++;
  18. }


 Puis ça

 
Code :
  1. <?php for($i=0;$i<count($id_produit);$i++){ ?>
  2. <?php echo $id_produit[$i]; ?></td>
  3. <?php } ?>
 

c'est mauvais ?


Message édité par networkinfo le 02-04-2015 à 14:08:19
n°2254816
mechkurt
Posté le 02-04-2015 à 14:27:34  profilanswer
 

Dans l'absolut, non ce n'est pas mauvais mais si tu ne fait aucune action en php sur tes tableaux (changement de tri, filtre ou autre), tu peux utiliser directement ton retour sql pour l'affichage...
 
Le plus couteux (hormis le poids de tes différents tableaux en mémoire) c'est sans doute ton :

Code :
  1. for($i=0;$i<count($id_produit);$i++){


Soit tu fait

Code :
  1. $nb_prod = count($id_produit);
  2. for($i=0;$i<$nb_prod;$i++){


Ou alors

Code :
  1. foreach($id_produit as $i => $value){


 
Personnellement j'ai tendance à faire :

Code :
  1. $t_prod = array();
  2. while($data = mysql_fetch_assoc($result)){
  3.     $t_prod[$data['id_produit']] = $data;
  4. }
  5. print_r($t_prod);


Message édité par mechkurt le 02-04-2015 à 14:28:00

---------------
D3
n°2254819
rufo
Pas me confondre avec Lycos!
Posté le 02-04-2015 à 14:58:49  profilanswer
 

Pareil, pour la récup de données provenant d'une BD, je fais un while. Ca évite de passer par un tableau intermédiaire qui peut être consommateur de mémoire.


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
mood
Publicité
Posté le 02-04-2015 à 14:58:49  profilanswer
 

n°2254821
networkinf​o
Posté le 02-04-2015 à 15:02:10  profilanswer
 

Merci les gars c'est sympa
 
Et pour la pagination ?
Vous faîtes un mysql_num_row sur une requête simplifiée et vous ajoutez le limit en conséquence ?

n°2254822
rufo
Pas me confondre avec Lycos!
Posté le 02-04-2015 à 15:04:32  profilanswer
 

Moi, je fais un COUNT() sur une requête simplifiée puis la vrai requête pour avoir les enregistrements à afficher.


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  optimisation requête mysql

 

Sujets relatifs
Optimisation d'une requête MySQL[MySQL] Optimisation de requete
Optimisation requête (Mysql)MySQL - Optimisation d'une requête avec plusieurs JOIN
Optimisation d'une requete mysql[MySQL] Besoin d'aide - Optimisation d'une requête très lourde
[MySQL] Optimisation requete sur ENORME table ...[PHP - MYSQL] optimisation d'une requete
[mysql]optimisation d'un requete[MySQL]optimisation requete
Plus de sujets relatifs à : optimisation requête mysql


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