Page 1 sur 1

Comptage du nombre de posts? Comment optimiser?

Posté : 06 août 2006, 01:01
par momox
Je suis en train de modéliser ma base de données en ce moment pour mon projet, mais je suis en train de me poser une question.
Suis-je obligé d'incrémenter une valeur dans un champ ou y a t'il une autre alternative afin de m'éviter de faire des requestes en trop?
@+

Posté : 06 août 2006, 09:36
par Cyrano
:shock: Si tu donnais quelques détails, ça aiderait à la compréhension : parles-tu de créer des clés primaires auto-incrémentées ? Dans ce cas, pourquoi est-ce que ça impliquerait des requêtes supplémentaires ?

Posté : 06 août 2006, 10:57
par momox
En fait, j'ai une table contenant mes news constituée de la manière suivante:
Image
Le champ tc_nb_news doit contenir le nombre de commentaires relatif a la news.
Donc la je ne pense pas qu'il existe une fonction pour faire en sorte que j'ai constament le bon nombre de commentaires dans ce champ.
Donc est ce que je dois faire a chaque suppression de commentaire un UPDATE avec une sous requête COUNT ?
@+

Posté : 06 août 2006, 11:03
par Cyrano
Règle importante en modélisation de base de données : autant que possible, ne JAMAIS stocker de valeurs calculées dans une table. Tu peux obtenir ce nombre avec des fonctions SQL du genre COUNT() dans une jointure éventuellement.

Donc ce champ n'a en fin de compte pas lieu d'être.

Si tu veux absolument avoir ce champ en permanence à jour, il va dans ce cas te falloir prévoir une procédure stockée qui va effectuer la requête de comptage suivie de la requête de mise à jour du champ approprié, et un trigger sur l'insertion de commentaires pour déclencher la procédure. Je ne suis pas du tout convaincu de l'intérêt de construire ce type de structure en dehors de l'aspect apprentissage.

Posté : 06 août 2006, 11:22
par momox
Je suis quelque peu habitué a cette structure :/
Dans le cas ou je suohaiterais utiliser les jointures selon ce que tu me dis, comment devrais-je faire car je n'y connais rien du tout en jointures... :/
@+

Posté : 06 août 2006, 12:27
par Cyrano
Qu'est-ce qu'une jointure ?

Dans un schéma, tu as plusieurs tables. Certaines tables comportent des données reliées aux données d'autres tables le plus souvent parce que le nombre des informations diffèrent. Prenons un exemple.

Supposons une table personnes : dans cette table, tu vas avoir un identifiant en clé primaire, mais également un nom et un prénom. Mais serait-il opportun de stocker un numéro de téléphone dans cette table ? Non, parce que selon la personne, tu peux ne pas avoir de numéro du tout ou bien en avoir trois, par exemple un numéro de domicile, un autre de portable, et un troisième de bureau. Comment procéder ? En créant une seconde table telephone : dans cette table, tu auras un identifiant, le numéro de téléphone, le type de numéro (domicile, portable, bureau, fax, autres...) et une clé étrangère : l'identifiant de la table personne.

Ainsi, lorsque la personne s'inscrit, elle peut avoir autant de numéros de tléphones que nécessaire ou ne pas en avoir. C'est la souplesse du système. Maintenant, as-tu besoin d'avoir dans la table personnes le nombre de numéros qu'une personne a ? Non, tu peux l'obtenir par calcul dans une requête avec jointure. La jointure va établir le lien entre chaque ligne de la table personnes et les lignes de la table telephones où on trouvera l'identifiant correspondant.

Pour l'exercice, créons deux tables :

Code : Tout sélectionner

CREATE TABLE `personnes` ( `pers_id` int(11) unsigned NOT NULL auto_increment, `pers_nom` varchar(32) NOT NULL, `pers_prenom` varchar(32) NOT NULL, PRIMARY KEY (`pers_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; CREATE TABLE `telephones` ( `tel_id` int(11) NOT NULL auto_increment, `pers_id` int(11) unsigned NOT NULL, `tel_num` char(12) NOT NULL, `tel_type` enum('domicile','portable','bureau','fax') NOT NULL default 'domicile', PRIMARY KEY (`tel_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Ajoutons quelques données;

Code : Tout sélectionner

INSERT INTO `personnes`(`pers_prenom`, `pers_nom`) VALUES('Jean', 'Peuplus'), ('Augustin', 'Connu'), ('Pierre', 'Affeu'); INSERT INTO `telephones`(`pers_id`, `tel_num`, `tel_type`) VALUES (1, '0145678910', 'domicile'), (1, '0678901234', 'portable'), (1, '0123456789', 'bureau'), (3, '0654321098', 'portable');
À ce stade, on voir rapidement que Jean Peuplus dispose de trois numéros, Pierre Affeu en a un seul, et Augustin Connu n'est pas joignable par téléphone.

Effectuer une jointure, consiste à relier les deux tables par l'élément commun aux deux : ici, l'identifiant de la table personnes se retrouve également dans la table telephones. Dans une requête SELECT, je vais indiquer les deux tables dans la clause FROM et je vais indiquer le critère de jointure dans la clause WHERE :

Code : Tout sélectionner

SELECT `pers_prenom`, `pers_nom`, `tel_num`, `tel_type` FROM `personnes` AS p, `telephones` AS t WHERE p.pers_id = t.pers_id;
Et je vais obtenir :

Code : Tout sélectionner

+-------------+----------+------------+----------+ | pers_prenom | pers_nom | tel_num | tel_type | +-------------+----------+------------+----------+ | Jean | Peuplus | 0145678910 | domicile | | Jean | Peuplus | 0678901234 | portable | | Jean | Peuplus | 0123456789 | bureau | | Pierre | Affeu | 0654321098 | portable | +-------------+----------+------------+----------+
Voilà, c'est pas plus sorcier que ça.

Maintenant, supposons que je veuille seulement connaitre le nombre de numéros disponible pour chaque personne, je me fous de ces numéros, je veux juste leur nombre : Là, ce sera un brin plus complexe parce que je veux également les personnes qui n'ont pas de numéros. Et pour corser un peu, je veux en premier ceux qui ont le plus de numéros : on va faire ce qu'on appelle une jointure gauche :

Code : Tout sélectionner

SELECT `pers_prenom` AS 'Prénom', `pers_nom` AS 'Nom', COUNT(`tel_id`) AS 'Nombre de numéros' FROM `personnes` AS p LEFT JOIN `telephones` AS t ON p.pers_id = t.pers_id GROUP BY `pers_nom`, `pers_prenom` ORDER BY COUNT(`tel_id`) DESC;
Et on va obtenir :

Code : Tout sélectionner

+----------+---------+-------------------+ | Prénom | Nom | Nombre de numéros | +----------+---------+-------------------+ | Jean | Peuplus | 3 | | Pierre | Affeu | 1 | | Augustin | Connu | 0 | +----------+---------+-------------------+
Et comme tu vois, je n'ai stocké nulle part le nombre de numéros, je l'ai obtenu par requête. C'est souple et rapide et ça laisse la liberté à chaque personne d'ajouter ou de retirer un de ces numéros sans que ton application doive déclencher une mise à jour automatique d'un champ particulier.

Posté : 06 août 2006, 14:07
par momox
Ok merci, c'est super, je connaissais pas trop ces moyens mais cela va m'être fort utile :langue:
@+

Posté : 06 août 2006, 18:37
par momox
Juste une question, je dois faire une liaison entre les tables ou pas?
@+

Posté : 06 août 2006, 18:39
par Cyrano
Qu'est-ce que tu entends par "liaison" au juste ?

Note de modération: réduis la taille de l'image dans ta signature, c'est trop grand, divise ça au moins en deux, merci.

Posté : 06 août 2006, 18:42
par momox
Une liaison entre deux tables, euh, comment dire...
Ce qui me permet de lier la table des membres et la table des news !
Si je puis résumer ainsi.

Posté : 06 août 2006, 20:29
par Cyrano
C'est la clé étrangère qui matérialise cette liaisons, il n'y a rien d'autre.

Alors éventuellement, tu peux ajouter l'intégrité référentielle en créant des tables de type InnoDB, mais d'abord ce sera moins performant que des tables MyISAM quoique ça puisse dans certains cas être nécessaire. Pour ma part, j'ai toujours préféré contrôler cette intégrité par programmation en restant logique. Ce que ça signifie (oui, je t'ai entendu murmurer "de quoi y cause lui") c'est que pour reprendre mon exemple personnes/telephone, si tu supprimes une ligne dans la table personnes, tu risques de te retrouver avec des lignes orphelines dans la table telephones : l'intégrité référentielle de tables InnoDB va bloquer la requête de suppression et retourner une erreur si des correspondances sont trouvées par MySQL. Donc, on supprimer D'ABORD les numéros de téléphones et ensuite seulement la personne à qui ça correspond.