[php/mysql] optimisation possible? - peut on diminuer le nb de requetes?

J’ai un script, très simple mais qui au final me donne un gd nombre de requete. Je me demandais donc si c’était possible de l’optimiser.

J’ai une table, construit comme suit:
id, titre, id-catégorie, id-membre, description,…

J’aimerai récuper, pour chaque catégorie, la liste des enregistrement répondant à la clause WHERE id-membre=‘X’.

En d’autre terme, je me retrouverai donc avec une liste comme suit

Catégorie A: le memebre X à 4 enregistrement dont

  • titre1
  • titre4
  • titre3
  • titre 20

Catégorie B: le membre X à 0 enregistrement

Catégorie C: le membre X à 2 enregistrement

  • titre 2
  • titre 19

A l’heure actuelle, la solution que j’ai trouvé est de faire n requete en fonction de mes n catégories.

je me retrouve donc avec des

  • SELECT id, titre, description FROM table WHERE membre="X" AND categorie = "A"
  • SELECT id, titre, description FROM table WHERE membre="X" AND categorie = "B"
  • SELECT id, titre, description FROM table WHERE membre="X" AND categorie = "C"

y a-t-il un moyen de diminuer le nb de requete (en les imbricants?..)

merci d’avance,

titib

Essaye l’opérateur IN :

WHERE x IN(‘foo’, ‘zzz’);

A noter que tes requêtes seront moins lourdes avec des entiers plutôt que des chaînes…

en faisant un gros select ordonné dans un ordre intelligent tu peux faire une seul requete en jouant sur les ruptures…

du style if( $last_id_membre != $rec["id-membre"]) { ben je cre un nouveau tableau etc…

ou alors tu stock tous dans des tableaux

$MEMBRES=array();

while (fetch…)
{
if(!isset($MEMBRES[$rec["id-membre"]])) $MEMBRES[$rec["id-membre"]]=array();

// j’ajoute c dont j’ai besoin
array_push($MEMBRES[$rec[“id-membre”]], <quelque chose> );

}

// un gros tableau avec tout ce dont j’ai besoin
print_r($MEMBRES);

$MEMBRES[$rec[“id-membre”]][] = …; est mieux (array_push = appel de fonction. [] = interne, du moins c’est comme ça que je le vois)

merci, je vais regarder ca de plus près…

Sinon, j’utilise des entier, mais je trouvais plus clair ds l’exemple d’utiliser des lettres que des chiffre :smiley:

edit: désolé d’être stupide, mais est-ce que vous pouvez me donner l’url du manuel de mysql où on parle de l’utilisation de IN. Pcq impossible de trouver (c’est super de chercher “in” dans un texte :p)… merci d’avance

edit2: est-ce plus gourmand en ressource de faire pls requete en mysql et d’avoir directement ce que j’ai besoin ou de n’en faire qu’une seule et de traiter les informations en php?

ça depend de la config mais a chaque requete sql il y a des echange reseau (sauf si local) des ouverture de session , du parsing , des gestion de cache etc …

donc vaut mieu une seul requete et faire du php derriere…

oki, c’est noté :wink: je vais essayer de faire ca…

et pour la requete IN? qsq il en est?

c’est tout simple :

SELECT * FROM matable WHERE truc IN(valeur1,valeur2,valeur3)

avec autant de valeurs que tu veux (il existe aussi NOT IN qui fait l’inverse :slight_smile: )

ca je sais, mais je parle de l’explication de “ce que c’est”… à quoi ca sert exactement. J’arrive pas à le trouver ni ds la doc, ni ds google…

c’est dans la doc, certainement dans la partie “opérateur de comparaison”

édition :
[i]expr IN (value,…)
Returns 1 if expr is any of the values in the IN list, else returns 0. If all values are constants, then all values are evaluated according to the type of expr and sorted. The search for the item is then done using a binary search. This means IN is very quick if the IN value list consists entirely of constants. If expr is a case-sensitive string expression, the string comparison is performed in case-sensitive fashion:
mysql> SELECT 2 IN (0,3,5,‘wefwf’);
-> 0
mysql> SELECT ‘wefwf’ IN (0,3,5,‘wefwf’);
-> 1

The number of values in the IN list is only limited by the max_allowed_packet value. From 4.1 (to comply with the SQL-99 standard), IN returns NULL not only if the expression on the left hand side is NULL, but also if no match is found in the list and one of the expressions in the list is NULL. From MySQL version 4.1, an IN() clause may also contain a subquery. See section 13.1.8.3 Subqueries with ANY, IN, and SOME.
expr NOT IN (value,…)
Same as NOT (expr IN (value,…)). [/i]

Tiens, j’avais pas filé le lien vers la doc?

http://dev.mysql.com/doc/mysql/en/comparison-operators.html

merci infiniement! finallement j’ai pas utilisé de IN, en réalité, j’ai meme essayé de l’utiliser sans arriver à en trouver l’interet dans mon cas, je me suis donc replié sur une simple jointure
du type

SELECT * FROM table1, table2 WHERE table1.`id`=table2.`nom` 

puis je stocke toutes les données dans un tableau à deux dimensions du type $tableau[cat][id] = titre que je parcours après avec la requete suivante

function afficher_tableau($tableau) 
{
	foreach ($tableau as $cle=>$valeur) 
	{
  if(is_array($valeur))
  {
  	echo '<strong>'. $cle .'</strong>
  	afficher_tableau($valeur);
  }
  else
  {
  	echo '<em>'. $cle .' : '. $valeur .'</em>';
  }
	} 
} 

mais maintenant se pose un autre problème et pas des moindres (je vous harcele légèrement avec mes histoires, mais vous y répondez tellement gentillement que je ne peux m’empecher de continuer):

Pour chaque titre, j’ai une table annexe où sont stocké des commentaires. Mon but est d’indiquer à coter de chaque titre, dans ma liste, le nb de commentaire lié à ce dernier.

Le problème est évident: je me retrouve à faire une requete par titre

ayant ma requete générale:


while(SELECT * FROM table1, table2 WHERE table1.`id`=table2.`nom`)
{

  // il me faudrait ici meme, stocker dans un autre tableau, le nb de commentaire, et cela pour chaque titre
   $tableau[Cat][id] = titre;
}

je suis donc obligé de faire une requete par boucle, et vu qu ma page est susceptible de contenir à terme des centaines de titre, je vais avoir une centaine de requete, uniquement pour avoir le nb de commentaires postés. Impenssable!

Deux solutions s’offre à moi:

  • oublier cette fonction qui somme toute n’est pas essentielle,
  • m’en remettre à vous…

Je commence par la seconde, et je me rabattrais sur la première si vraiment vous n’avez pas d’idées.

Elle est caca ta jointure. Utilise JOIN.

les group by tu connais pas ?

ex

select a.id_table_a, count(b.id_table_b)
from table_a a left join table_b b on a.id_table_a = b.id_table_a
group by a.id_table_a

merci :jap:

j’vais finir par m’acheter un bouquin sur mysql, ca me ferait pas de tort :wink: à force de bidouiller comme ca :stuck_out_tongue:

edit: ce qui n’empeche que j’ai un problème, auquel vous pourrez sans doute m’aider. Je ne sais jamais où trouver l’info. Par exemple, la doc de mysql n’explique absolument pas à quoi sert exactement group by, ou join… Il n’explique que sa synthaxe. Dès lors, cmt je dois faire pour comprendre moi :frowning:

Quite à acheter un bouquin sur le SQL, prends en un sur le SQL standard :slight_smile: pas mySQL.

Pour l’info :

http://sql.developpez.com/

merci de ton lien (je sais que c’est tjs les meme que tu donnes et redonne, mais bon, je pense pas tjs a aller voir mes classiques)…
tu as un livre à conseiller (sinon celui qui est conseillé sur le site)?

sinon, niveau ressource, tu dis que ma jointure est merdique. Je le concoi tout à fait mais en quoi l’utilisation de JOIN me la rend plus propre? (et pi je comprend pas trop cmt ca marche)… je continue à m’acharner, mais si tu as deux minutes pour m’expliquer… :smiley:

edit: j’ai compris l’histoire du group by mais je comprend pas vraiment le LEFT JOIN…

Qu’on soit clair : j’avais fait le test, JOIN et le produit cartésien c’est normalement équivalent au niveau temps d’éxécution.

Sauf qu’avec JOIN (et INNER JOIN) tu mets tout ce qui concerne les jointures dans un seul côté, ce qui favorise la relecture de la requête. Ce qui n’est pas le cas de la tienne. D’autant que si tu veux ajouter des conditions au WHERE, tu dois faire un AND ( … ) et pour peu que tu te gourres, tu fais un OR ou alors, ton AND ne prend que la première opérande disponible et ça ramouille. Bref…

La syntaxe du JOIN est très simple :

SELECT *
FROM ta A, tb B
WHERE A.id = B.id

Donne :

SELECT *
FROM ta A
INNER JOIN tb B ON A.id = B.id

A noter qu’avec ça, tu peux faire des zolis LEFT JOIN, ou RIGHT JOIN selon le besoin. Par exemple, si tu veux récolter les sujets d’un forum, et récolter le nom de l’utilisateur, tu utiliseras typiquement un LEFT JOIN pour tout le temps prendre les sujets du forum même s’ils ne correspondent pas à un utilisateur.

en gros ce que veut dire sans-nom (sisi il a voulu dire quelque chose, enfin je crois)

c que un bete produit cartesien amene en resultat des lignes qui correspondent a des enregistrement present dans les DEUX table (donc une intersection en terme ensembliste)

alors qu avec un left join on ramene dans tous les cas tous les enregistrements de la table maitre et ceux de la table left joinée si il y en a