Lancer une discussion
Répondre

   NPDS - Optimisations simples
Envoyé le  25-09-2008  à  22:16    
Freud
Freud
    611

Bonjour,

je vais dresser ici quelques principes simples d'optimisation des fichiers NPDS.
De quoi gagner en tailles de fichiers, en requêtes SQL, interprétation des pages par les navigateurs, etc. En bref, gagner en temps de chargement et soulager le serveur !

Seul problème, le temps. Il faudra beaucoup de patience. J'ai choisi pour ma part de m'attaquer au nettoyage au fur et à mesure que je dois exploiter certains fichiers pour revoir les mises en page, modifier des fonctionnalités, etc.

  Les fonctions inutiles :


Le gros avantage d'NPDS est qu'il est très complet, ce qui peut vite devenir un gros inconvénient. NPDS à en effet la réputation d'être gourmand en ressources. Cela ne veut pas dire qu'il est préférable de changer de crèmerie, bien au contraire !
Il est rare qu'un utilisateur d'NPDS ai besoin de la totalité des fonctionnalités disponibles, mais nos attentes sont différentes, d'où l'intérêt d'avoir un générateur de portail aussi complet que celui d'NPDS, mais aussi de faire rapidement le tri.

Exemple :
Le traducteur
Il vous sera facile de savoir si oui ou non votre site sera destiné, même à très long terme d'accueillir des populations d'autres pays et donc d'autres langues que le français.
Si vous êtes certains de ne jamais avoir besoin d'offrir d'autres langages d'exploitation, alors pourquoi demander X fois par pages la vérification du langage choisi et d'afficher le texte en fonction ?

Si je prend l'exemple du fichier admin/links.php (sur lequel je suis actuellement), on y trouve nombre de fois les appels aux fonctions suivantes :

- adm_translate("Texte à traduire") (17 caractères sans le texte + 2 de concaténation avant et après = 19)
- aff_langue($variable) (12 caractères sans la variable + concaténation)

Multipliez ces chiffres par le nombre de fois ou ces fonctions apparaissent et vous vous retrouvez rapidement avec des milliers de caractères inutiles, donc de Ko. A cela s'ajoute bien entendu le travail supplémentaire du serveur qui appel autant de fois ces fonctions.

Il suffit donc de supprimer ces fonctions pour ne laisser la place qu'aux textes à afficher. Pourquoi ne pas en profiter pour revoir la concaténation ?



  La concaténation :



Les pages sont encodées à l'ancienne, c'est à dire :
echo "<table width=\"100%\" cellspacing=\"2\" cellpadding=\"2\" border=\"0\"><tr><td class=\"HEADER\">\n";

Si vous écrivez cette même ligne de la manière suivante ...
echo '<table width="100%" cellspacing="2" cellpadding="2" border="0"><tr><td class="HEADER">';

... vous gagnez là encore 12 caractères sur 1 seule ligne

Passez les retours charriots (actuellement sous la forme <br />) en <br> et vous gagnez rapidement des centaines d'octets sur une seule page.

Pour les retours charriot, il suffit généralement de faire un Ctrl+H (suivant votre éditeur de texte) et d'inscrire les caractères à modifier pour régler l'affaire (20 secondes montre en main) :



En ayant simplement fait ces quelques modifications, je suis passé de 48,2 Ko à (pas finit , pour l'instant 46,6 avec 1/3 de fait),
plus les gains en ressources serveur.



  Requêtes SQL :



Il y a plein de manières d'arriver au même résultat, mais toutes ne se valent pas, surtout en matière de base de données. La qualité des requêtes SQL est très importante pour les performances de votre site. Non seulement des requêtes mal choisies ou mal utilisées ralentirons sensiblement le chargement de vos pages mais aussi et surtout elles pourront amener rapidement votre serveur à saturation et paralyser votre site !
Lorsque vous créez de nouvelles fonctionnalités, n'hésitez pas à entreprendre des recherches sur le net ou à vous documenter en matière d'optimisation SQL. Les ouvrages ne manquent pas. Si vous site vient à rapidement voir son trafic augmenter, vous serez de toute manière obligé d'y passer alors ... n'attendez pas que ce soit votre site qui vous le demande !
Vous perdrez plus de temps à vous réimprégner de vos codes pour tout corriger ensuite (et dans la panique d'un serveur qui sature) qu'en vous égarant quelques temps dans vos bouquins ou pages web au fur et à mesure que vous développez une page.

Sans entrer dans les détails purement techniques de l'optimisation SQL (de plus je n'ai pas la prétention d'être un as dans le domaine, et encore moins de pouvoir vous faire une leçon), une des règles simple est de ne sollicité dans vos requêtes que les champs qui vous intéressent, et éviter tant que possible l'emploi des * dans vos requêtes.

Exemple :
Toujours dans mon fichier admin/links.php, fonction links(), vous trouverez des requêtes de type :

$result=mysql_query("select * from links_links");

$numrows = mysql_num_rows($result);
$result = mysql_query("select * from links_modrequest where brokenlink=1");
$totalbrokenlinks = mysql_num_rows($result);
$result2 = mysql_query("select * from links_modrequest where brokenlink=0");
$totalmodrequests = mysql_num_rows($result2);


Ces trois requêtes successives ne servent qu'à compter un nombre de résultats de recherche. Il est donc inutile de demander au serveur de répertorier tous les champs disponibles pour chacun des résultats :

- Table "links_links" : 15 champs
- Table "links_modrequest" : 10 champs X 2 requêtes

= 35 champs interprétés multiplié par le nombre de résultats, contre 1 champ nécessaire seulement par requête.
Préférez donc l'utilisation d'un champ spécifique de votre table à la place de *, et de préférence autre-chose que du texte. L'ID de la table sera parfait.

Ex : $result=mysql_query("select lid from links_links");



Voici donc pour quelques exemples types applicables à tous vos fichiers.
Je m'efforcerais d'ajouter d'autres exemple concrets de codes à modifier au fur et à mesure de mes avancées.
Je vous invite à faire de même lorsque vous tombez sur des requêtes trop gourmandes en indiquant la page concernée.

++

   [ Message modifié par  Freud  le  25-09-2008  à  22:26 ] 

Attachement(s) : notepad.jpg   
Envoyé le  26-09-2008  à  01:43    
Freud
Freud
    611

  Passer de 23 à 2 requêtes pour le même résultat



L'exemple traité ici concerne les menus déroulants de l'annuaire, mais est valable pour tous les autres menus déroulants gérés par base de donnée (catégories des articles, etc.)

Fichier admin/links.php, function links() >> // Add a New Link to Database

Nous avons dans cette fonction la création d'un menu déroulant avec les catégories de votre annuaire et les sous-catégories associées, le tout affiché par ordre alphabétique des catégories et des sous-catégories.
Pour ce faire, nous avons tout d'abord une 1ère requête répertoriant nos catégories.
On lance une boucle pour afficher ces catégories, à l'intérieur de laquelle se trouve une seconde boucle contenant une nouvelle requête afin de répertorier les sous-catégories. Cette dernière sera donc répétée autant de fois que vous avez de catégories principales.
Si vous avez par exemple 10 catégories dans votre annuaire, vous exécuterez 1 + 10 requêtes SQL !

Il est possible de faire la même opération avec 1 seule requête et 1 seule boucle !

Le code actuel :
$result=mysql_query("select cid, title from links_categories order by title");


echo 'Catégorie : <select class="TEXTBOX_STANDARD" name="cat">';

while(list($cid, $title) = mysql_fetch_row($result)) {

echo '<option value="'.$cid.'">'.$title.'</option>';

$result2=mysql_query("select sid, title from links_subcategories where cid='$cid' order by title");

while(list($sid, $stitle) = mysql_fetch_row($result2)) {
echo "<option value=\"$cid-$sid\">$title / $stitle</option>";
}
}



Code optimisé :
       $menu_deroulant=mysql_query("select c.cid, c.title, s.sid, s.title from links_categories c, links_subcategories s where c.cid=s.cid order by 2,4");


echo 'Catégorie : <select class="TEXTBOX_STANDARD" name="cat">';

while(list($cid, $title, $sid, $stitle) = mysql_fetch_row($menu_deroulant)) {

if ($affiche!=$cid) {
echo '<option value="'.$cid.'">'.$title.'</option>';
}
echo '<option value="'.$cid.'-'.$sid.'">'.$title.' / '.$stitle.'</option>';

$affiche=$cid;
}

< br>
Explications :

"select c.cid, c.title, s.sid, s.title from links_categories c, links_subcategories s where c.cid=s.cid order by 2,4"

Dans cette même requête, je vais chercher tous les résultats dont nous avons besoin dans les 2 tables qui nous intéressent. c.cid désigne par exemple le champ cid de la table c définie plus loin : from links_categories c.
c.title provient également de la table c, donc links_categories, s.sid et s.title de la table s soit la table links_subcategories définie de la même manière à la suite de links_categories.

where c.cid=s.cid sert à trier les résultats. Sans cette clause, vous obtiendriez pour chaque catégorie l'ensemble des sous-catégories, y compris celles des autres catégories. Vous pouvez faire un essai en supprimant cette clause pour constater la différence.

order by 2,4 permet le classement par ordre alphabétique, en priorité sur les titres des catégories (2), puis des sous-catégories.


La boucle !

Afin d'éviter de voir apparaitre le nom d'une catégorie devant chaque sous-catégorie correspondant, j'ai ajouté la condition if ($affiche!=$cid) suivi de l'affichage de la catégorie.

- Au premier passage de la boucle, $affiche n'est pas encore définie. La condition s'en trouve remplie donc la catégorie est affichée.
- A la suite, toujours au premier passage de la boucle, j'affiche la 1ère sous-catégorie.
- En fin de boucle, je définit $affiche comme étant égale à l'ID de la catégorie.
- Au second passage de la boucle, la catégorie est toujours la même, avec cette fois une 2ème sous-catégorie à afficher.
$cid à toujours la même valeur, $affiche étant alors égale à $cid, la condition n'est plus remplie, donc pas d'affichage de la catégorie, mais seulement de la sous-catégorie suivante.
- ...

Lorsque toutes les sous-catégories sont parcourues, on change de catégorie ($cid), $affiche est toujours égal au $cid précédant et la condition pour l'affichage de la catégorie se trouve à nouveau remplie.


Ce n'est pas finit !
Plus loin sur notre page est afficher à nouveau ce même menu déroulant, avec en prime cette fois une requête qui ira vérifier la présence de catégories
Pour le faire maintenant mais pas la 1ère fois ?
Mieux, à quoi sert un annuaire s'il ne contient pas de catégories ? Peu importe, nous faisons tous nos boulettes. C'était pour voir si l'on suivait

Ça ce passe juste après // Modify Category

On peut donc commencer par supprimer la 1ère requête servant à compter le nombre de catégories et indirectement à vérifier leur présence.
Ne pas oublier d'enlever la condition associée.

Par simple précaution j'ai fait le choix d'initialiser la variable $affiche ayant toujours comme valeur le dernier ID de catégories. Ce n'est normalement pas utile puisque nous repartons avec notre 1ère valeur.

Ce qui nous donne :
// Modify Category


echo '<table width="100%" cellspacing="2" cellpadding="2" border="0"><tr><td class="HEADER">';
echo 'Modifier la Catégorie';
echo '</td></tr></table>';

echo '<form method="post" action="admin.php">';
echo 'Catégorie : <select class="TEXTBOX_STANDARD" name="cat">';

$menu_deroulant=mysql_query("select c.cid, c.title, s.sid, s.title from links_categories c, links_subcategories s where c.cid=s.cid order by 2,4");

$affiche='';
while(list($cid, $title, $sid, $stitle) = mysql_fetch_row($menu_deroulant)) {

if ($affiche!=$cid) {
echo '<option value="'.$cid.'">'.$title.'</option>';
}
echo '<option value="'.$cid.'-'.$sid.'">'.$title.' / '.$stitle.'</option>';

$affiche=$cid;
}
< br>

Toujours en prenant l'exemple d'un annuaire avec 10 catégories, nous avions :

1 + 10 =11 requêtes
1 (vérif) + 1 + 10 = 12 requêtes


Ce qui nous faisait bien un total de 23 requêtes SQL sur une même page contre 2 maintenant !



   [ Message modifié par  Freud  le  26-09-2008  à  02:14 ] 

Lancer une discussion
Répondre