[symfony] récupérer les données d'une jointure

Mammouth du PHP | 965 Messages

08 avr. 2010, 11:48

@agité : faire le choix d'un ORM, c'est s'assoir sur les optimisations de base. Ne serait que le chargement des données en objet, ça a un coup en terme de performance. Heureusement, ce cout se rattrape au niveau de la facilité d'utilisation et de la maintenabilité.
Donc, soit on utilise un ORM, et on est prêt à sacrifier quelques performances, soit la performance est un impératif sur toute une application, et on s'en passe.
La solution intermédiaire et de court-circuiter l'ORM sur les requêtes les plus lourdes et les plus sensibles.

@marwina32 affiche nous la requête générée, et essaye de l'exécuter à la main.
Ma foi avant de faire du Doctrine je faisais du Propel en Symfony 1.0 et je faisais bien les select et autres optimisations, je ne vois pas en quoi c'est contradictoire d'utiliser un ORM et de faire de l'optimisé en fait. C'est comme dire tu utilise un framework alors tu peux faire n'importe quoi vu que le framework te feras quand même gagner en perf sur les couches basses.

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

08 avr. 2010, 11:50

Est-ce que tu as aussi modifié la manière d'exécuter la requête ? Comme je te le conseille dans mon 1er post ?
return $q->execute();
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

08 avr. 2010, 11:53

@agité, je ne dit pas que tu peux faire n'importe quoi, et que l'ORM s'arrangera pour que ça soit optimisé. Je dit que l'intérêt d'un ORM, c'est de manipuler les données comme des objets. Si tu veux optimiser au mieux ta couche modèle, un ORM n'est pas un bon choix puisqu'il entraine une surcharge de traitement, particulièrement au niveau de l'hydratation des objets.

De plus, penser sa couche modèle en fonction de la vue n'est pas du tout MVC friendly, et risque de te poser de gros soucis de factorisation de code ou de maintenance de code.
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Mammouth du PHP | 965 Messages

08 avr. 2010, 12:00

@agité, je ne dit pas que tu peux faire n'importe quoi, et que l'ORM s'arrangera pour que ça soit optimisé. Je dit que l'intérêt d'un ORM, c'est de manipuler les données comme des objets. Si tu veux optimiser au mieux ta couche modèle, un ORM n'est pas un bon choix puisqu'il entraine une surcharge de traitement, particulièrement au niveau de l'hydratation des objets.

De plus, penser sa couche modèle en fonction de la vue n'est pas du tout MVC friendly, et risque de te poser de gros soucis de factorisation de code ou de maintenance de code.
Ok donc si je vois des coup de 300 requêtes par pages avec du select * et pleins de jointures j'ai pas de quoi m'inquiéter vu qu'il y a l'ORM ?

Eléphanteau du PHP | 20 Messages

08 avr. 2010, 12:07

Est-ce que tu as aussi modifié la manière d'exécuter la requête ? Comme je te le conseille dans mon 1er post ?
return $q->execute();
oué, je l'ai déjà modifié

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

08 avr. 2010, 12:12

@agité : tu me demande s'il vaut mieux faire un select * plutôt qu'un select ciblé, je te répond que dans le cadre d'un ORM, non. Toutefois, même dans le cas de l'utilisation d'un ORM, faire des jointures est plus que conseillé. D'ailleurs, tu pourras constater que dans la requête que je propose, je laisse la jointure. Il faudrait peut être voir à ne pas déformer mes propos, si tu tiens à comprendre ce que je veut dire.

@marwina32 : dans ton indexSuccess.php, regarde le nombre d'éléments présents dans ta variable :
il y a <?php echo count($ruptures) ?> résultats à afficher
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Eléphanteau du PHP | 20 Messages

08 avr. 2010, 12:20

lorsque j'ai exécuté la requête à la main, j'ai modifier le titre des tables en miniscule pour qu'elle soit exécutable
alors dans ArticlesTables.class.php je l'ai changé en miniscule
//ArticlesTables.class.php
->from('articles a')
->innerJoin('a.rayon r')
dans ce cas, j'ai eu comme résultat:

Code : Tout sélectionner

500 | Internal Server Error | Doctrine_Table_Exception Unknown relation alias rayon
j'ai essayé de les changer dans le fichier schema.yml:

Code : Tout sélectionner

articles: connection: doctrine tableName: articles columns: ..... relations: rayon: foreignAlias: rayon local: codearticle foreign: coderayon type: many rayon: connection: doctrine tableName: rayon columns: .....
puis j'ai regénéré le schema.yml
alors, j'aurai une nouvelle erreur!!!!!

Code : Tout sélectionner

Fatal error: Call to undefined method articlesTable::getArticleRupture() in /home/sfprojects/MoreHard/apps/frontend/modules/tableau2bord/actions/actions.class.php on line 20
:x nottant que je n'ai rien changé dans l'action!!
public function executeIndex(sfWebRequest $request)
  {
  	$this->ruptures = ArticlesTable::getArticleRupture();
  }

Mammouth du PHP | 965 Messages

08 avr. 2010, 12:42

@agité : tu me demande s'il vaut mieux faire un select * plutôt qu'un select ciblé, je te répond que dans le cadre d'un ORM, non. Toutefois, même dans le cas de l'utilisation d'un ORM, faire des jointures est plus que conseillé. D'ailleurs, tu pourras constater que dans la requête que je propose, je laisse la jointure. Il faudrait peut être voir à ne pas déformer mes propos, si tu tiens à comprendre ce que je veut dire.

@marwina32 : dans ton indexSuccess.php, regarde le nombre d'éléments présents dans ta variable :
il y a <?php echo count($ruptures) ?> résultats à afficher
Ne te méprends pas je tente pas de déformer ce que tu dis néanmoins je ne comprends pas ta vision des choses c'est pourquoi je te pose la question pour un cas précis c'est à dire que l'ORM se doit de charger un certains nombre d'entrées sur du multi-tables avec pleins de champs. SI ça ne sert à rien de faire du select fieldilike je peux comprendre pas besoin de s'énerver. C'est juste que je vois une page ou ya 300 requêtes en select * alors je me dis ce serait bien d'optimiser.

Donc la réponse serait oui optimiser pour le nombre de requêtes mais faire du select filedilike c'est du pipi de chat en gain de perf.

Eléphanteau du PHP | 20 Messages

08 avr. 2010, 12:46

@marwina32 : dans ton indexSuccess.php, regarde le nombre d'éléments présents dans ta variable :
j'ai eu un 0 comme affichage #-o

Eléphanteau du PHP | 20 Messages

08 avr. 2010, 13:07

lorsque j'avais géré le schema.yml contenant les nouvelles modifications en miniscule, j'ai eu une nouvelle base: Basearticles.class.php avec deux nouveaux fichiers: articles.class.php et articlesTables.class.php,
j'ai modifier le fichier articlesTables.class.php comme suit:
<?php

class articlesTable extends Doctrine_Table
{
	static public function getArticleRupture()
	{
	 $q=Doctrine_Query::create()
           ->select('a.codearticle,
                    a.ref,
                    a.designationarticle,
	            a.designationlongarticle,
	            a.stockreel,
	            a.minStock,
	            a.stocktheorique,
	            a.gestionstock,
          	    a.bloque,
            	    r.libellerayon')
           ->from('articles a')
           ->innerJoin('a.rayon r')
           ->Where('a.GestionStock=?','1')
           ->andWhere('a.Stockreel <=?','a.MinStock');
         return $q->execute();
	}
}
pour le résultat j'ai eu le même résultat, et encore j'ai eu un 0 comme résultat du :
?php echo count($ruptures) ?>

Eléphanteau du PHP | 20 Messages

08 avr. 2010, 14:13


je l'ai éxécutée à la main, et elle m'a affiché les données sélectionnées

je suis désolée,
je n'ai pas exécuté cette requête à la main, j'ai exécuté celle-ci:
Select articles.CodeArticle AS 'CodeArticle',
articles.REF AS 'Reférence'  ,
articles.Designationarticle AS 'Désignation'  ,
articles.DesignationLongArticle AS 'Désignation Longue'  ,
articles.Stockreel AS 'Stock réel' ,
articles.MinStock  AS 'Stock Min' ,
articles.Stocktheorique AS 'Stock théorique'  ,
articles.GestionStock AS 'Géré.Stock'  ,
articles.Bloque AS 'Bloqué'  ,
rayon.Libellerayon AS 'Rayon'  
From articles , rayon 
WHERE articles.Coderayon = rayon.Coderayon 
AND  articles.GestionStock = '1' 
AND articles.Stockreel <= articles.MinStock
mais lorsque j'exécute la requête du ArticlesTables.class.php:
static public function getArticleRupture()
	{
	 $q=Doctrine_Query::create()
           ->select('a.codearticle,
                    a.ref,
                    a.designationarticle,
	            a.designationlongarticle,
	            a.stockreel,
	            a.minStock,
	            a.stocktheorique,
	            a.gestionstock,
          	    a.bloque,
            	    r.libellerayon')
           ->from('articles a')
           ->innerJoin('a.rayon r')
           ->Where('a.GestionStock=?','1')
           ->andWhere('a.Stockreel <=?','a.MinStock');
         return $q->execute();
	}
la fenêtre du browser Mysql s'est fermée, j'ai répété l'opération pas mal de fois, et j'ai toujours le même résultat

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

08 avr. 2010, 14:15

@marwina32 : bon, alors le soucis se passe entre la récupération des données et la transmission au contrôleur.
Par contre, là, je seche un peu :-k
La requête exécutée seule retourne des enregistrements, mais pas via Doctrine ...
Tu es sûre de l'exécuter sur la bonne base ?

@agité : je ne m'énerve pas, je met juste le doigts sur un point qui me parrait sensible dans notre échange, à savoir ne pas deviner entre les mots que je peux dire.
Alors, pour commencer, si tu as 300 requêtes sur une page, ORM ou pas, il y a une optimisation à faire, et c'est certainement dû à une jointure manquante. Et, toujours ORM ou pas, les jointures sont toujours un point à penser à l'avance, et il faut toujours garder un oeil sur l'évolution du nombre de requêtes sur une page.
Maintenant, mon propos est que dans le cadre de l'utilisation d'un ORM, il vaut mieux faire des SELECT *, qui vont remplir correctement les objets, plutôt que des SELECT ciblé, qui vont remplir partiellement les objets, et qui sera source d'erreur quand tu appelleras le getter d'un attribut non rempli. Dans l'optique objet d'un ORM, charger des demi-objets est très dangereux puisque tu n'es pas sensé savoir quels sont les attributs qui vont être affiché, ni comment.
Ceci dit, il est toujours possible d'exécuter quelques requêtes de manière "non objet" (comprendre retourner un tableau de données plutôt qu'un tableau d'objet) et c'est quelques fois bien pratique, pour des requêtes sensible à optimiser. Mais cette pratique doit rester annexe dans le cadre de l'utilisation d'un ORM. Sinon, il n'a plus d'intérêt, et il suffirait d'utiliser un DBAL à ce compte là.
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Eléphanteau du PHP | 20 Messages

08 avr. 2010, 14:33

@marwina32 : bon, alors le soucis se passe entre la récupération des données et la transmission au contrôleur.
Par contre, là, je seche un peu :-k
La requête exécutée seule retourne des enregistrements, mais pas via Doctrine ...
Tu es sûre de l'exécuter sur la bonne base ?
non, je pense que le soucis provient de la requête elle-même car lorsque je l'exécute depuis le browser mysql:
Select articles.CodeArticle AS 'CodeArticle',
articles.REF AS 'Reférence'  ,
articles.Designationarticle AS 'Désignation'  ,
articles.DesignationLongArticle AS 'Désignation Longue'  ,
articles.Stockreel AS 'Stock réel' ,
articles.MinStock  AS 'Stock Min' ,
articles.Stocktheorique AS 'Stock théorique'  ,
articles.GestionStock AS 'Géré.Stock'  ,
articles.Bloque AS 'Bloqué'  ,
rayon.Libellerayon AS 'Rayon'  
From articles
innerJoin rayon 
WHERE articles.GestionStock = '1' 
AND articles.Stockreel <= articles.MinStock
la fenêtre se ferme, j'ai répété l'opération plusieurs fois, et j'ai eu le même résultat, même si je ne fais pas une selection personnalisée, j'ai le même résultat

ViPHP
ViPHP | 5462 Messages

08 avr. 2010, 14:34

t'as essayé mon truc ?

Eléphanteau du PHP | 20 Messages

08 avr. 2010, 14:35

Tu es sûre de l'exécuter sur la bonne base ?
oué, je suis sur la bonne base