Association de tables et lecture sur une page

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : Association de tables et lecture sur une page

Re: Association de tables et lecture sur une page

par zeus » 19 déc. 2010, 15:59

La solution "pour chaque ligne de la requête 1, je fait une requête" est très très très très (très, ...) mauvaise.
Pourquoi ? Le nombre de requêtes !!

Si tu as 10 billets, tu auras 11 requêtes (la 1ere requête pour les billets, et une requête par billetst), pour 100 billets : 101 requêtes, ...
Quand on sais que ce qui prend le plus de temps dans un programme, ce sont les accès aux fichiers sur le disque et les requêtes en bases de données, on vois que la solution de multiplier les requêtes est très très (bref, vous m'avez compris) mauvaise.

La bonne solution est de faire une jointure, mais de tenir compte de ça quand tu parcours la liste de tes résultats.

Voici un petit exemple pour éviter les soucis, tout en optimisant le nombre de requêtes :
<?php

// Utilisation d'un LEFT JOIN pour remonter les billets sans commentaire
// NB : utiliser JOIN, LEFT JOIN, OUTER JOIN est plus optimisé qu'une jointure par le WHERE
$requete = <<<EOF
	SELECT 
		billets.id, billets.titre, billets.contenu, DATE_FORMAT(billets.date_creation, \'%d/%m/%Y à %Hh%imin%ss\') AS date_creation_fr, 
		commentaires.id, commentaires.auteur, commentaires.com, commentaires.id_billet 
	FROM billets LEFT JOIN commentaires ON billets.id = commentaires.id_billet 
	ORDER BY date_creation_fr DESC 
	LIMIT 0, 5
EOF;

// Cette requête va retourner plusieurs fois les mêmes billets, s'ils ont plus de 1 commentaire.
// Il est donc nécessaire de retravailler le résultat pour avoir la liste des billets, et les commentaires qui leurs sont associés
$reponse = $bdd->exec($requete)
 	OR die(print_r($bdd->errorInfo()));


// Initialisation du tableau qui contiendra le résultat de la requête
$a_billet = array();

foreach( $reponse->fetch() as $ligne )
{
	$id_billet = $ligne[1];
	$id_commentaire = $ligne [5];
	
	// Si le billet n'a pas déjà été parcouru, on le créé dans le tableau.
	// Ici, il est important de noter que je créé un tableau destiné à contenir les commentaires de ce billet
	if( array_key_exist($id_billet, $a_billet) )
	{
		$a_billet[$id_billet] = array(
			'id' => $ligne[1],
			'titre' => $ligne[2], 
			'contenu' => $ligne[3], 
			'date_creation_fr' => $ligne[4],
			'commentaires' => array(), 	// Création du tableau destiné à contenir les commentaires
		);
	}
	
	// Ajout du commentaire dans le billet
	$a_billet[$id_billet]['commentaires'] = array(
		'id' => $ligne['5'],
		'auteur' => $ligne['6'],
		'com' => $ligne['7'],
	);
}


// Affichage du tableau chargé
echo '<pre>';
print_r($a_billet);
echo '</pre>';

Re: Association de tables et lecture sur une page

par epommate2 » 15 déc. 2010, 07:03

Oui, mais ramener pour chaque commentaire l'intégralité du billet, ca s'appelle : une perte de temps !

D'ailleurs, je ne vois pas trop comment limiter le nombre de lignes retournées sur le nombre de billets ?

Re: Association de tables et lecture sur une page

par devlop78 » 15 déc. 2010, 01:30

Une requête pour chaque ligne de résultat retourné ? Ca s'appelle une jointure.

Ta requête de ta requestion n'est pas du tout une jointure mais une simple boucle.

Un truc que j'avais fait, tout à fait anodin mais pas mal pour voir comment le moteur SQL réagit, est un SELECT id FROM table1, table1, table1;

Et on remarque rapidement qu'il ne fait jamais que :
Pour chaque table 1 {

Pour chaque table 1 {

Pour chaque table 1 {

// Faire ce que l'utilisateur demande

}

}

}
Un left join, right join ou inner join fera ton bonheur, en te retournant tout en un seul jeu de résultant, ce qui alégera les allés-retour avec le sgbd, la compilation des codes SQL, etc ...

Re: Association de tables et lecture sur une page

par BlenderOfWebCode » 13 déc. 2010, 17:47

Merci

Re: Association de tables et lecture sur une page

par epommate2 » 13 déc. 2010, 17:26

Une requête qui te ramène les billets :

Code : Tout sélectionner

SELECT billets.id, billets.titre, billets.contenu, DATE_FORMAT(billets.date_creation, \'%d/%m/%Y à %Hh%imin%ss\') AS date_creation_fr ORDER BY date_creation_fr DESC LIMIT 0, 5
POUR CHAQUE billet :

Code : Tout sélectionner

SELECT commentaires.id, commentaires.auteur, commentaires.com, commentaires.id_billet WHERE commentaires.id_billet = $id_du_billet

Re: Association de tables et lecture sur une page

par BlenderOfWebCode » 13 déc. 2010, 17:10

Merci pour cette très bonne analyse!

Euh... mais au final, ça donnerait quel type de structure?

Désolé, en tant que débutant, je me permets d'être énervant :oops:

Re: Association de tables et lecture sur une page

par epommate2 » 13 déc. 2010, 16:47

C'est normal, il fait exactement ce que tu lui demande :

La jointure agit comme une sorte de produit :
Pour chaque ligne de la table "billet" :
- cherche moi les lignes dans la table commentaire dont l'id du billet égale l'id_billet du commentaire

Si la table billet a les lignes suivantes :
1 billetA
2 billetB
3 billetC

Et la table commentaire:
1 commentaireA1
1 commentaireA2
2 commentaireB1

Il te ramènera :
1 billetA commentaireA1
1 billetA commentaireA2
2 billetB commentaireB1


Essaye plutôt de faire deux requêtes :
- une qui te ramène les billets;
- une qui te ramène les commentaires pour chacun des billets.

Association de tables et lecture sur une page

par BlenderOfWebCode » 13 déc. 2010, 15:15

Bonjour,

je souhaite afficher sur une seule page des billets ainsi que leurs commentaires. Avec la requête que j'ai actuellement, il s'affiche plusieurs fois le même billet selon le nombre de commentaire qui lui est associé :oops: .

Voici la requête en question :
$reponse = $bdd->QUERY('SELECT billets.id, billets.titre, billets.contenu, DATE_FORMAT(billets.date_creation, \'%d/%m/%Y à %Hh%imin%ss\') AS date_creation_fr, commentaires.id, commentaires.auteur, commentaires.com, commentaires.id_billet FROM billets, commentaires WHERE billets.id = commentaires.id_billet ORDER BY date_creation_fr DESC LIMIT 0, 5')  or die(print_r($bdd->errorInfo()));
Ce n'est pas brillant :? ...

Est-ce que des âmes bienveillantes pourraient m'aider?