Vous n'êtes pas identifié(e).
Merci JC pour votre réponse. J'avais oublié à quel point il fallait avoir le coeur bien accroché pour poster sur ce forum pour débutants...On a souvent l'impression d'être une grosse merde inutile. Bref.
Ce premier site de cuisine était - et est toujours - bien évidemment amateur. Il m'a servi à apprendre les bases de la programmation HTML / CSS / PHP / MySQL / javascript(jQuery). Je n'ai jamais eu la prétention d'aller concurrencer marmiton ou quoique ce soit d'autre. Le trafic augmente progressivement parce qu'il n'est pas trop mal référencé (enfin derrière marmiton et 750g bien sûr) et qu'il offre sérieusement quelques bonnes idées...A la question "Avez-vous fait au préalable une étude à savoir si le SGBDR choisi est capable de répondre au cahier des charges de votre applicatif au moins en terme de charge" la réponse est donc non, et je ne suis même pas sûr de la comprendre. Toutefois anticiper tout ce que vous dites dans la première partie de votre réponse m'intéresse énormément et pour l'avenir je vous serais reconnaissant de bien vouloir m'orienter vers des ouvrages, sites ou articles permettant de "prévoir [ ...] l'architecture même du site en fonction de ses contraintes de production et ses spécificités métier". Sérieusement, ça m'intéresse.
A part ça : tout a commencé quand j'ai reçu la semaine dernière un mail de mon hébergeur qui me prévenait que le trafic de ce site commence à excéder ce qui est prévu dans le contrat initial (quasi gratuit) et qu'ils m'encouragent à les contacter blablabla pour discuter d'un changement d'offre. Toutefois - disent-ils - ils m'encouragent aussi à vérifier l'efficacité dudit site en termes de sollicitation du serveur, taille des images, etc. Dans la foulée j'ai utilisé des outils comme YSlow sur Firefox et des sites comme GTmetrix qui me disent qu'en gros, l'affichage des pages est ralenti par différents facteurs, dont un peut-être trop grand nombre de requêtes serveur (et ces saletés de modules sociaux Facebook et Google+). Je me suis donc repenché sur différentes pages dont la fameuse recette.php et ses 6 requêtes. Il m'a naïvement semblé intelligent d'essayer de les regrouper toutes en une seule vu que c'est la page la plus utilisée sur le site et qu'au final, toutes ces requêtes concernent une même recette. Les causes de ma démarche s'arrêtent là. Débutant, quoi...
Donc si je comprends bien, on ne peut pas édicter une règle générale qui dirait "moins y a de requêtes, mieux c'est" ? Chercher à tout combiner en une requête est potentiellement inutile ? Quels sont les facteurs à regarder ? Comment tester ? Où puis-je apprendre cela ?
Merci pour la précision sur le sens des égalités, j'avoue avoir oublié ce détail. Je restais bêtement sur les bases mathématiques qui disent que peu importe le sens de l'égalité, vu que c'est une égalité.
Tout faux, les tables n'ont pas de champs mais des colonnes, si ta requête comporte vraiment des étoiles sur le site c'est contre-productif pour soulager le serveur.
UI m'sieur, sur la page en vrai y a pas d'étoile. Et pardon pour l'erreur de langage.
il n' y a pas lieu d'en encadrer la valeur avec des quotes ,'.
Cela dit, ça n'explique pas ce nombre conséquent de lignes retournées. Là on dirait qu'il fait un produit cartésien de toutes les jointures, bizarre. Tu devrais essayer ta requête avec une seule jonture, puis deux, puis trois, etc. pour voir à partir d'où ça commence à déraper.
Je fais ça dans la foulée et viens poster l'évolution du résultat. Je suis presque soulagé de voir qu'en fait je dois pas être trop à côté de la plaque dans la première requête, cela dit.
EDIT :
En fait ça foire dès la deuxième jointure et il me fait bien un produit cartésien.
Rien que là j'ai 60 résultats. Que se passe-t-il ?
Peut-être qu'en l'occurrence le multi-requêtage n'était pas une si mauvaise idée que cela. L'information qu'il faut quand il faut (remember, just keep it simple, stupid).
Ah. Comment je peux savoir ce qu'il vaut mieux faire, du coup ? Je pensais que diminuer le nombre de requêtes ne pouvait pas de toute façon être une mauvaise chose. Me trompé-je ?
Où as-tu pêché cette ânerie ?
Il me semblait l'avoir constaté les rares fois où j'ai eu besoin de le faire. Je dois confondre avec autre chose.
Bien entendu, toutes les colonnes visées par le ORDER BY sont indexées dans les tables, n'est-ce pas ?
Hum...Je vais vérifier de ce pas.
Edit :
Tant qu'à créer un index pour optimiser les requêtes, quelles colonnes choisir pour être le plus efficace possible ? Juste nomDeLaTable_position ou bien j'ai intérêt à le faire sur plusieurs colonnes ?
Bonjour !
Me voilà de retour sur ce forum pour implorer de l'aide. Je croyais avoir passé ce cap, mais en fait non...et ça me navre. J'essaye de me consoler en me disant que c'est quand même relativement avancé...
J'explique :
Je reprends mon premier site de cuisine (opérationnel). Je cherche à l'optimiser parce que maintenant qu'il y a un peu de trafic dessus, je tue le serveur. La page la plus vue est naturellement la page "recette.php". Cette page, à partir d'un identifiant recette_id obtenu à partir d'un GET, fait 5 ou 6 requêtes pour afficher toutes les infos utiles : les ingrédients, les ustensiles, les étapes, etc.
Je me dis que "tiens, j'ai du temps à perdre, maintenant que je sais faire, paf, je vais faire tout ça en une seule requête". Et là, c'est le drame : en fait, je ne sais toujours pas faire ça correctement.
Structure de la BDD :
- j'ai une table "principale" appelée recettes qui contient un recette_id et les infos uniques de chaque recette sur une ligne : l'auteur, le nom, la catégorie, etc.
- Toutes les autres tables concernées sont de type "1 à plusieurs" : elles ont toutes une colonne "recette_id" clé étrangère et un "nomDeLaTable_id" unique.
En une seule requête, je souhaite donc choper toutes les infos de toutes les tables concernées pour une recette donnée : les infos de la ligne de la table recettes, les X lignes d'accompagnements, les Y étapes, etc.
Quand je fais :
Il me retourne 7920 résultats pour UNE recette. Ce qui me semble relativement absurde vu qu'il y a en gros une cinquantaine d'infos différentes pour chaque recette (en comptant les étapes, les ingrédients, etc.)
Bref : comment réécrire cette requête pour avoir un résultat cohérent et optimisé pour le serveur ?
Deuxième question :
Dans un monde idéal où je réussis à faire une requête correcte : comment utiliser au mieux le résultat lors de l'affichage de la page ? Comment à partir du résultat de la requête afficher les X ustensiles au bon endroit et les Y étapes à un autre ? Quelle est la technique la plus efficace ?
Question bonus :
Il m'est souvent arrivé de devoir utiliser plusieurs fois le résultat d'une requête sur une même page. Quel est le meilleur moyen pour ce faire ? Une fois le résultat utilisé dans un while, on ne peut plus le réutiliser ailleurs. Faut-il mettre le résultat de la requête dans un premier tableau ? Ou faire un reset($requete) ? Ou utiliser mysql_data_seek() ? Ou quoi que ce soit d'autre ?
Voilà voilà.
Merci de ne pas me jeter de cailloux.
Edit : à l'attention de MK : oui je sais, il ne faut pas mettre de * dans une requête mais là c'est juste pour raccourcir un peu sinon il y a trop de champs...
Bonjour,
J'ai une vraie question de débutant.
Mon premier site est plus ou moins fini, c'est à dire que je corrige deux trois bugs par-ci par-là et j'améliore mes requêtes (par ex. remplacer les * dans les SELECT par ce que j'ai effectivement besoin de récupérer) et le référencement du site.
Pour l'instant il est hébergé par Free et je ne rencontre pas de soucis de navigation particuliers. Toutefois, l'absence du mod rewrite pour améliorer les url des pages, la mauvaise gestion des JSON et l'absence d'un nom de domaine propre m'incitent à me pencher sur la question d'un changement d'hébergeur.
J'examine donc une offre et je vois "nombre de connexion simultanées autorisées à la base de données MySQL : 4". Bon, certes, d'une part je ne prévois pas un succès immense de mon site, d'autre part une connexion est censée durer quelques millisecondes.
Et donc justement, voilà mes questions : comment être sûr que mes requêtes et mes connexions sont suffisamment bonnes pour qu'elles ne durent que le temps nécessaire et qu'elles se terminent bien comme il faut ? Que je n'utilise que le strict nécessaire et pas de superflu qui ralentirait le processus ? Y a-t-il des trucs à connaitre en particulier pour optimiser les connexions ? Y a-t-il moyen de monitorer les connexions effectuées par le site ?
Si ces questions sont très stupides, je m'en excuse ^^
Merci pour vos conseils.
Pardon pour la nouvelle question stupide, mais je n'ai pas encore organisé le traitement négatif du formulaire, j'attendais de savoir formuler correctement la requête, uniquement via l'interface de mysql. Tu veux quand même que je mette la partie positive ? Ou le plus simple est peut-être encore que je vous donne l'adresse de la page du site ?
Ce qu'il y a, c'est que cette même bdd renvoie les bonnes données quand je fais la première requête AVEC.
Le $nom contient une ligne facultative avec un AND recette_nom LIKE '%$rechRecette%' si l'utilisateur tape un nom dans la case prévue pour.
Le $classe contient un paramètre permettant de filtrer les recherches par classe de recettes (entrées/plats/desserts/apéros : "AND recette_classe = 'entree'" par ex.).
le $valeurs est un implode des valeurs cochées par l'utilisateur séparées par des " OR ingredient_nom = ".
Le $nb contient le nombre de valeurs cochées.
Là, je n'ai pas constaté la moindre erreur de cohérence. Si le problème de la recherche SANS venait de la table, est-ce que ça pourrait marcher aussi bien pour la partie AVEC ?
Je précise que quand je fais la recherche AVEC simplifiée (juste un SELECT recette_id FROM recettes_ingredients WHERE ingredient_nom = '28' OR ingredient_nom = '31' HAVING COUNT etc.) j'obtiens les mêmes résultats.
Pour la partie SANS, quand je fais une requête plus ardue inspirée de celle ci-dessus (donc avec les noms des ingrédients et des recettes pour plus de lisibilité) sans GROUP BY pour tâcher de comprendre ce qu'il fait, en ne disant seulement que je ne veux pas de farine, il est tout fier de me retourner par exemple toutes les lignes d'ingrédients des crêpes SAUF celle qui concerne effectivement la farine. Donc il comprend vaguement ce que je veux, c'est juste qu'il s'en fout. Je pense qu'il rit en me voyant rager. Le pire c'est qu'il encadre les ingrédients histoire de bien me montrer qu'il sait. Il m'en veut pour toutes les approximations que je lui ai fait subir. Hum pardon, je pète les plombs.
Donc je suis ouvert à l'utilisation du Wall. Quelles parties du code faut-il que j'y mette ?
En fait, quelque soit la valeur de l'ingredient_id et quelque soit leur nombre, les résultats restent les mêmes. Strictement. Que je cherche de la farine, du poivre ou quoique ce soit d'autre, les mêmes : c'est à dire toutes les recettes qui ont des ingrédients (oui dans la base j'en ai qui ont juste servies à tester les différents champs, donc qui n'ont pas forcément d'ingrédient).
Bon ça fait un moment que je m'énerve dessus. Je viens de faire une base de tests avec des nombres au pif pour les recettes, avec des ingrédients au pif. Et quand je fais la requête, j'ai des résultats cohérents. Mfff. Quelqu'un saurait pourquoi sur une table de tests faite en 3 secondes ça marcherait et pas sur la vraie ? Vous voyez une raison possible ?
Doit y avoir un truc en plus...Quand je fais "SELECT recette_id FROM recettes_ingredients WHERE (ingredient_id <> '28' AND ingredient_id <> '31') GROUP BY recette_id" les résultats ne sont pas cohérents, je ne devrais pas avoir les crêpes là-dedans (entre autres erreurs)...Grmbll.
Argh je suis pourtant sûr d'avoir testé cette possibilité... Je vais recommencer, j'ai dû me planter ailleurs. Merci. Encore.
Bonjour,
J'ai réussi à faire la partie positive (AVEC ces ingrédients) grâce aux conseils donnés ci-dessus, et je bûche sur la partie négative (SANS ces ingrédients) avant d'entamer la partie utilisant les deux. Et je lutte et m'interroge.
Concernant la partie négative, ne faut-il pas sélectionner toutes les recettes qui ont l'un de tous les autres ingrédients via un "simple" (ingredient_nom = 'truc' OR ingredient_nom = 'machin'...etc) comprenant tous les ingrédients sauf ceux sélectionnés par l'utilisateur ? Ca me semble être toutefois très long et bancal comme principe et si c'est la solution, je n'ose envisager celle pour la recherche utilisant les AVEC et les SANS... Comment faire autrement ? Je pensais naïvement qu'une simple négation par != dans la requête positive marcherait mais les résultats sont incohérents.
Merci pour vos avis éclairés
Oui je sens que je repasserai par là quand il s'agira de faire des "cet ingrédient, celui-ci aussi, mais pas celui-là"...
Merci, en tout cas. Après les premiers tests, ta recommandation semble marcher parfaitement.
Merci ! Les notions de GROUP BY et HAVING me semblaient nébuleuses, ça va être l'occasion de les tester de près !
Merci d'avoir répondu.
En l'état, je crois que mes trois tables ont bien la structure que tu me décris. Autant à mes débuts mes tables étaient chaotiques et mal pensées, autant grâce notamment à M "maiiiitre" K je pensais avoir réussi à optimiser toute cette pagaille...Je suis passé de une table à 125 champs (véridique ^^) à 6 tables puis enfin 3 tables...La table recettes_ingredients ressemble à ça (sans les noms d'ingrédients entre parenthèses, bien sûr) :
recette_id ingredient_id quantite unite remplacant facultatif
80 28(sel) bla bla bla bla
80 31(farine) bla bla bla bla
81 28(sel) bla bla bla bla
81 31(farine) bla bla bla bla
82 28(sel) bla bla bla bla
Du coup, comment dois-je formuler ma requête pour que ça marche si je ne peux pas faire de AND au sein de la même table ? J'avoue ne pas comprendre.
Bonjour,
Pour ceux qui suivraient mon évolution via ce forum, je suis toujours sur mon projet de site de cuisine. Il avance bien, merci. Un de ces jours je mettrai le lien pour que vous puissiez venir rire...
Bref, là je travaille sur une fonction de recherche de recettes par ingrédients.
Ce n'est pas pertinent dans mon principal souci, mais sur le principe, ça utilise AJAX et des checkbox divisées en deux catégories : ce que je veux, et ce que je ne veux pas.
Je teste actuellement la forme que doit prendre la requête directement sur MySQL.
Quand il y a un seul ingrédient à chercher, ceci marche très bien :
Explications :
3 tables concernées : recettes, recettes_ingredients, et ingredients. La table recettes_ingredients comporte notamment un champ ingredient_id et un champ remplacant, comportant tous les deux des ID d'ingrédients (id différents). Il me parait nécessaire que l'on puisse obtenir un résultat "du moment que l'ingrédient est soit principal, soit remplaçant".
Il me retourne bien la liste de toutes les recettes qui comportent de la farine.
Mais quand je veux ajouter un deuxième ingrédient, par exemple le sel, il ne m'affiche aucun résultat alors qu'il devrait y en avoir 3. J'utilise pour ça "WHERE ingredient_nom = 'farine' AND ingredient_nom = 'sel'" et j'espérais pouvoir ensuite ajouter autant de "AND ingredient_nom = 'machin'" tant que l'utilisateur coche des checkbox. Il y a donc forcément quelque chose que je fais mal dans cette condition, mais je n'arrive pas à mettre le doigt dessus. Auriez-vous l'amabilité de m'indiquer où est ma faute ?
Merci !
Il me reste encore tant de choses à apprendre, Maiiiiiiiitre
Oui mais pourtant quand je fais un "while ($ingredients = mysql_fetch_assoc($exeIngredients)){echo $ingredients['ingredient_nom'];}, cela m'affiche bien la liste des ingrédients que le membre n'a pas, mais quand je fais la même chose avec 'ingredient_id', il n'affiche rien, alors que spontanément je pensais qu'il m'afficherait la liste de leur ID.
C'est donc là que je fais quelque chose de mauvais ?
EDIT : Bon en mettant un alias après ing.ingredient_id AS ingID et ensuite en affichant 'ingID', ça me les met bien comme il faut. Il devait y avoir une confusion entre les mbIng.ingredient_id et les ing.ingredient_id. C'est la bonne technique pour s'en sortir ?
Bon j'ai honte. En exploitant les résultats, je me rends compte que je ne peux pas utiliser l'ingredient_id de la table ingredients.
Je suis partagé entre deux explications :
- ou bien j'ai bouletté dans l'exploitation de la requête avec une faute de frappe ou quelque chose comme ça (ce qui m'arrive TRES fréquemment),
- ou bien la condition WHERE mbIng.ingredient_id IS NULL empêche de récupérer les ID des ingrédients affichés. Vu que c'est ma première requête de ce type, je ne saurais trop dire si c'est ça...
Pourtant, j'ai quand même besoin de pouvoir exploiter l'ID de l'ingredient que le membre ne possède pas encore, vu que en cliquant sur cet ingrédient, le membre l'ajoute à sa liste, et donc à la table mbIng, dans la colonne ingredient_id.
Comment puis-je sortir de cette impasse ?
J'ai rajouté la condition AND mbIng.membre_id = "'.$_SESSION['membre_id'] à cette LEFT OUTER JOIN et Ô Miracle, les résultats semblent cohérents !
Merci (encore !) Maljuna.
Hum maintenant passons à l'exploitation des résultats pour gérer l'affichage des ingrédients par classes sans répéter à chaque fois le nom de la classe...
A bientôt, donc
Bonjour,
Aujourd'hui, j'essaye d'optimiser une page qui actuellement fonctionne, mais qui fera bondir les puristes si ils en voient le code...
Bref, j'ai besoin des infos de trois tables :
- une table ingredients qui contient un id, un nom, et une classe_id (clé étrangère)
- une table classes, qui contient aussi un id, un nom complet et un nom raccourci
- une table membres_ingredients qui contient un membre_id et un ingredient_id
L'objectif final est l'affichage d'une liste présentée par classes contenant tous les ingrédients que le membre N'a PAS.
L'idée est de lui permettre de cliquer sur les éléments de cette liste pour justement indiquer que dorénavant il les a.
La technique initiale utilisée était sur le principe de faire une première boucle WHILE sélectionnant les classes, puis dans cette boucle de sélectionner les ingrédients appartenant à cette classe avec un WHERE et d'affiner la liste avec un AND ingredient_id NOT IN et un autre SELECT prenant les ingrédients possédés par le membre.
C'est fonctionnel, mais euh...pas très optimisé, on va dire.
Je voudrais donc faire une requête jointe sur trois tables. Je me débrouille à peu près avec les deux premières mais je ne sais pas comment formuler qu'il faut filtrer avec la troisième.
Pour l'instant j'ai...
...et évidemment, ça ne m'affiche pas ce que j'attends, vu que de toute façon la condition ON n'est pas bonne.
Donc justement, comment la rendre bonne ? C'est possible de faire un != ? Quand j'essaye, ça ne m'affiche absolument pas ce que j'attends non plus, bien sûr.
Bref, j'apprécierais énormément vos lumières !
Merci !
Bonjour,
J'ai réorganisé mes tables d'une façon plus logique, il faut bien l'admettre, et ça marche plus simplement au niveau des requêtes. Merci, notamment à Maljuna Kris pour ces précieux conseils.
Toutefois, le dernier bug mentionné reste présent :
Prenons un exemple : les 5 premiers ingrédient sont indispensables, le 6ème est facultatif. L'utilisateur coche une petite case pour indiquer le caractère facultatif de l'ingrédient 6. Tous les champs sont nommés ingredient[] et facultatif[]. Quand j'affiche ligne par ligne les valeurs des deux arrays ingredient[] et facultatif[], les ingrédients sont bien nommés un à un dans l'ordre. Par contre, pour facultatif, le 0 a le caractère facultatif (F), et les autres ne l'ont pas. Alors que ça devrait être l'inverse.
Je pense que le problème vient du fait qu'il faudrait qu'à chaque ligne d'ingrédient (ie ingredient + facultatif) le champ facultatif[] ait une valeur dans tous les cas, que l'auteur de la recette coche la case ou non. Ainsi on garderait une cohérence entre l'ingrédient 0 et le facultatif 0, entre le 1 et le 1, etc.
Le truc, c'est que je ne sais pas comment faire ça. Comment donner une valeur par défaut cachée à un champ, notamment une checkbox ? Ou est ce que ça peut être effectivement réglé par une table ? Si oui je ne vois pas comment. Merci de bien vouloir m'éclairer.
Ah mais je suis à fond pour éviter tous les tracas. J'ai voulu commencer ce site pour appliquer progressivement la masse d'information que j'ingurgite depuis des mois en programmation, et plus je le développe, plus je m'y noie, surtout sur le php.
Bon pour revenir à cette réponse, cher Maljuna Kris, que vouliez-vous dire exactement ? Comment organiser la table pour que cela fonctionne ?
Bonjour,
Je viens de me rendre compte d'un bug en faisant des tests. L'insertion via des valeurs de formulaires mises en array se passe bien, merci pour votre aide.
Mais :
Pour chaque ingrédient proposé par l'utilisateur, j'ai un champ checkbox qui demande si l'ingrédient est facultatif ou pas. La valeur est correctement traitée mais mal insérée, et je n'ai pas encore les connaissances nécessaires pour formuler correctement la requête. Il compte bien le nombre de checkboxs checkées et insère le bon nombre dans la table, mais pas au bon endroit. Il les met systématiquement dans les colonnes correspondantes 0 1 2 3 etc au lieu de les mettre là où le numéro de l'ingrédient correspond effectivement. Pour plus de clarté, un exemple : sur un test avec 6 ingrédients nommé ing0 à ing5 dont un sur deux checké, il insère 'F' dans les colonnes "ingredientFacultatif0" 1 et 2, et I (pour Indispensable) dans les colonnes 3 4 5, au lieu de mettre F I F I F I.
Pour l'instant, ma requête ressemble à ça :
Quelqu'un pourrait-il m'éclairer sur l'origine du problème et le moyen de le résoudre ? Merci.
Excellent, Pierrot, tu parles par énigmes, ça me met la tête en ébullition pour une journée, après ^^..."Qu'a-t-il bien pu vouloir dire ?"
EDIT : bon j'ai un nouveau souci (mais jQuery m'aidera sans doute )
Dans ma requête sql, comment désigner le champ - par exemple - ingredient$i pour y mettre la valeur $i tirée du array ingredient du formulaire ?
Bon je floode mon propre topic...
J'ai quelques questions à propos de la gestion des données du formulaire en tableau :
- comment contrôler la saisie utilisateur ? Les techniques habituelles de html_special_char et autres ne fonctionnent pas.
- comment faire réapparaitre la saisie au bon endroit ? Si mon utilisateur fait une erreur, je veux faire en sorte qu'il n'ait pas tout à retaper, et donc qu'il revienne sur la page formulaire avec les champs qu'il a déjà remplis. Les champs traités "normalement" fonctionnent bien, mais pour les données en array, il indique "Array". Je dois encore faire une erreur de parenthèses, crochets ou autres apostrophes...
Il y en aura d'autres plus tard