Optimiser ses développements

L'optimisation du code et des temps de réponse est un sujet rarement évoqué dans le développement web.
L'optimisation est souvent réservée aux applications professionnelles sensibles. Pourtant tout webmaster est concerné directement par cette question.
Le développement des accès haut-débit depuis près de 2 ans a 2 conséquences majeures :
- l'augmentation du nombre d'internautes et donc de visiteurs potentiels
- l'augmentation du temps moyen de connexion et donc du nombre de pages vues

Les hébergeurs ont pour la plupart déjà fait profiter leurs clients d'augmentation de la bande passante. Par exemple chez OVH, la bande passante fournie avec les serveurs dédiées a pratiquement été multipliée par 10 en 2004, sans supplément de prix.
La bande passante qui était encore récemment un point critique ne pose plus réellement de problème, sauf pour certaines applications spécifiques de téléchargement ou de radio en ligne par exemple.
En revanche, la puissance des serveurs n'a pas suivi le même rythme de croissance que l'augmentation de la population d'internautes : on considère généralement que la puissance des processeurs double tous les 18 mois selon la loi de Moore qui prédit "seulement" que "le nombre de transistors par cicuit de même taille va doubler tous les 18 mois".
C'est bien la puissance CPU qui est devenu le facteur limitant aujourd'hui.
Les hébergeurs sont très attentifs à la consommation CPU des sites sur hébergements mutualisés. En cas de dépassement des limites, l'accès peut être coupé.
Pour un site sur serveur dédié, l'optimisation du code permet de proposer à ses visiteurs un site rapide et fiable et d'éviter la surenchère technologique et les coûts associés à l'augmentation des capacités matérielles.

Une optimisation réussie apporte pour vos visiteurs un plus grand confort de navigation et pour vous une meilleure maîtrise des coûts d'hébergement et surtout une plus grande sérénité par rapport aux risques de plantages du site.

Nous allons voir dans ce tutorial comment mesurer les performances d'un site et les différents moyens d'optimiser les temps de traitement coté SQL, PHP et configuration.
Je n'ai pas la prétention d'être exhaustif dans ces quelques pages. Je donne simplement quelques solutions que j'ai mises en application moi-même avec un certain succès au niveau PHP, MySQL et Apache.
N'hésitez pas à me signaler les éventuelles erreurs et vos solutions d'optimisation.

Voici le sommaire de cet article (les prochaines parties suivent bientôt).
1 - Mesurer les performances
Etape indispensable pour optimiser : être capable de faire l'état des lieux et de mesurer les améliorations.

2 - Optimiser MySQL
Le moteur SQL est certainement l'élément qui a le plus fort potentiel d'optimisation.

3 - Utiliser le cache MySQL
A partir de la version 4 de MySQL, une gestion de cache ouvre de nouvelles possibilités.

4 - Utiliser les caches fichiers
Les principes du cache et une solution détaillée avec Cache Lite.

5 - Optimiser le serveur
Il existe de nombreuses astuces efficaces pour accélérer les traitements sur le serveur.

Structure d'une base de données

Introduction
Devant le succès des premiers tutoriaux sur le PHP, voici une introduction aux bases de données.
L'avantage considérable d'un langage serveur comme le PHP est qu'il peut conserver des données saisies par des utilisateurs, les traiter, les trier et les afficher aux autres visiteurs. Avec le PHP, on peut donc faire des forums, des livres d'or, des sondages. Bref tout ce qui est interactif sur le web.

Pour sauver des données, beaucoup pensent que le meilleur moyen est d'utiliser des fichiers texte. C'est une solution possible. La solution la plus souple et nécessitant le moins de développements est la base de données. Toutes les fonctions de sélection, de tri, de recherche, d'insertion, de modification et de suppression sont possibles grâce aux langage de requêtes SQL (Structured Query Language).

C'est donc l'utilisation des bases de données MySQL avec PHP que nous allons aborder dans ce tutorial.

PHP est très souvent utilisé en association avec le système de gestion de base de données (SGBD) MySQL. Les hébergeurs qui supportent le PHP proposent tous MySQL. De même le package EasyPHP que nous avons déjà vu dans le tutorial Introduction au PHP installe automatiquement MySQL. Nous sommes donc prêts à démarrer avec une base de données.

Avertissement 1 : La lecture des tutoriaux "JavaScript et PHP", "Introduction au PHP" et "Traiter des données en PHP" est un pré-requis absolument nécessaire.
Avertissement 2 : Ce tutorial est une vulgarisation des bases de données. L'objectif est de comprendre leur fonctionnement et leur intérêt (par rapport aux fichiers texte par exemple) et d'apprendre à les utiliser. Celui qui vient me parler de 3ème forme normale ou de méthode MERISE dans ce contexte n'a rien compris à l'esprit de cette section du site...
Avertissement 3 : Les bases de données sont très puissantes, mais il faut un minimum de concentration et de travail pour comprendre. N'imaginez pas que vous allez faire un script de forum en 30 minutes. Que les fainéants passent directement à autre chose.

Plan du tutorial :
1 - Structure d'une base de données
2 - Utilisation de PHPMyAdmin
3 - Accès à une base de données en SQL
4 - Accès à une base de données en PHP


Structure d'une base de données
A quoi sert une base de données
Une base de données est destinée :
- à stocker des données structurées et organisées - à manipuler ces données grâce a leur organisation.

Une base de données contient des tables ayant des rapports logiques entre elles.
Une table peut être comparer à un tableau de données.

Dans ce tutorial, nous allons prendre l'exemple de la base de données Catalogue qui contient les tables Catégorie et Produit. L'objectif est donc de créer une base de données qui contiendra toutes les informations d'un catalogue de produits.
On a souvent tendance à confondre base et table. Ce sont pourtant 2 objets bien différents.
Une base regroupe des tables sur le même domaine d'informations (ici le domaine catalogue de produits).

Table et clé primaire
La table "Categorie", dont le but est de lister toutes les catégories du catalogue, est définie comme ceci :

Identifiant Nom
1 Processeur AMD
2 Processeur Intel
3 Mémoire RAM
4 Carte mère

Chaque ligne d'une table correspond à un enregistrement. Ici un enregistrement est une catégorie.
Une colonne est une propriété d'un enregistrement.
Cette table contient 2 colonnes :
La colonne "Nom" sert à enregistrer le nom d'une catégorie sous forme de texte.
La colonne "Identifiant" est un nombre entier qui sert à identifier de manière unique un enregistrement (ou ligne) de la table.
On appelle cet identifiant unique la clé primaire de la table. On pourrait également identifier une catégorie par son nom. Mais il faut éviter car :
- le nom peut changer (erreur de saisie par exemple)
- le SQL est beaucoup plus rapide pour manipuler des entier.

L'identifiant d'une table permet également de faire des liens avec d'autres tables. Nous allons voir comment faire un lien entre un produit et sa catégorie.

Liens entre tables
La table "produit", dont le but est de contenir les produits d'un catalogue, est définie comme ceci :
Identifiant Nom Prix Vignette Categorie
1 AMD Athlon XP 2000 + 98 vignette/athlon.gif 1
2 Intel Pentium 4 2GHz 245 vignette/p4.gif 2
3 Intel Céléron 2 GHz 145 vignette/celeron.gif 2
4 Barette DDR 512 Mo PC2100 56 vignette/ddr.gif 3

Ici aussi, une ligne correspond à un enregistrement, c'est-à-dire à un produit.
- Nous retrouvons également l'identifiant unique (ou clé primaire)
- La colonne Nom contient le nom du produit
- La colonne Prix contient le prix sous forme numérique
- La colonne Vignette contient l'adresse d'une image correspondant au produit
- La colonne Categorie contient un nombre qui est un lien vers la clé primaire de la table Categorie. Vous remarquez qu'on n'enregistre pas le nom de la catégorie dans cette colonne, mais juste un identifiant. Dans ce cas, la colonne est une clé externe vers la table Categorie.
Voici les avantages d'utiliser une clé externe :
- Gain de place de stockage (Enregistrer un entier est bien moins volumineux que d'enregistrer un libellé complet)
- Gain de mise à jour (Si un jour le libellé Processeur Intel doit devenir Processeur INTEL, il suffit de changer la ligne 2 de la table Categorie et tous les produits de la catégorie 2 profiteront de la mise à jour)
- Gain de rapidité (Manipuler un entier est plus rapide que manipuler du texte)

Modèle de données
Un modèle graphique de représentation du schéma de la base avec les liens entre base serait :

Modèle de données
Les tables sont représentées par des boîtes avec leur nom et leurs colonnes.
La colonne Identifiant est soulignée car elle correspond à la clé primaire.
La clé externe Categorie de la table Produit est reliée par une flèche à la table Categorie pour montrer le lien.
La simple flèche vers la table Categorie montre qu'un produit peut être attaché à une seule catégorie.
La double flèche vers la table Produit montre qu'une catégorie peut concerner plusieurs produits.

On pourrait enrichir la base en ajoutant une table des marques de produits avec une clé externe entre un produit et sa marque. Le modèle de données serait alors :

Modèle de données

Questions fréquentes sur les bases de données
* Le nombre de produits n'est pas stocké dans la table Categorie car on peut le retrouver autrement.
Il suffit de compter le nombre de produits par colonne Categorie.
On sait par exemple qu'il y a 2 produits de la catégorie "Processeur Intel".
En règle générale, il faut éviter de stocker des données redondantes qui peuvent être retrouvées autrement. Sauf dans certains cas, si le moyen de retrouver cette donnée est gourmand en ressources CPU ou si cette donnée est souvent demandée.

* Il n'est pas utile de gérer les numéros d'identifiant manuellement. Le système de base de données le gère automatiquement en incrémentant l'identifiant d'une unité à chaque insertion de ligne.

* Les caractères spéciaux (accents, espace, ...) sont à éviter dans les noms des tables et des colonnes.
Il est egalement conseillé d'éviter d'appeler une table ou une colonne par un mot réservé du SQL.