Page 1 sur 1

Module de statistiques - Optimiser le temps de calcul

Posté : 20 mai 2007, 19:20
par Belisarius
Bonjour à tous,

J'ai créer un module de statistiques pour un projet personnel qui comptabilise le nombre de téléchargements effectués, qui fonctionne de la façon suivante :

• 1 table SQL qui stocke un DATETIME et l'ID du document téléchargé

• 1 fichier PHP qui boucle sur un nombre de périodes (20) avec un incrément (1 jour) sur cette table et qui effectue pour chaque période une requête du genre :
SELECT COUNT(dl_date) FROM matable WHERE UNIX_TIMESTAMP(dl_date) > '$dateDebut' AND UNIX_TIMESTAMP(dl_date) < '$dateFint'
Tout marche très bien mais le script mets déjà 0,8 secondes alors que je n'ai que 6000 hits sur 4 jours donc je n'ose pas imaginer sur 20 jours voir 20 semaines.

Je voulais donc savoir s'il exister une façon moins gourmande en temps de faire tout ça.
Je souhaite seulement obtenir un tableau à la fin du calcul qui me donne pour chaque période le nombre de téléchargement pour cette période.

Merci d'avance

Posté : 20 mai 2007, 20:29
par Hubert Roksor
Il faut faire en sorte que ta requête utilise l'index sur "dl_date" (évidemment, ne pas oublier de créer un index sur "dl_date"). Pour cela il ne faut pas utiliser de fonction SQL mais comparer la colonne directement. Par exemple, pour les enregistrements du mois de mai :

Code : Tout sélectionner

WHERE dl_date BETWEEN '2007-05-01 00:00:00' AND '2007-05-31 23:59:59'
De plus, COUNT(*) est un petit peu plus rapide que COUNT(dl_date), donc autant l'utiliser.

Pour le truc concernant les périodes/incrément je n'ai pas vraiment compris, est-ce que tu peux donner un exemple des données que tu récupères s'il te plait ? Dans tous les cas, ton but est de tout récupérer en une seule requête, quitte à ajouter une colonne qui sert à grouper les résultats. Par exemple, au lieu d'utiliser la date exacte de chaque enregistrement, tu pourrais utiliser une colonne supplémentaire qui contiendrait le numéro du jour. Pour simplifier les calculs on peut imaginer que tous les jours font 86400 secondes (et donc occulter les changements d'heures ou la seconde qu'on rajoute de temps à autres) et stocker la valeur du timestamp UNIX divisé par 86400 dans une colonne de type SMALLINT UNSIGNED, ce qui devrait te laisser jusqu'au milieu du 22ème siècle pour changer de type de stockage. En PHP, le numéro du jour pourrait être obtenu par
floor(time() / 86400)
...à toi d'améliorer selon les besoins. Ensuite pour récupérer le nombre de téléchargements par jour sur ces 20 derniers jours

Code : Tout sélectionner

SELECT jour, COUNT(*) FROM table WHERE jour BETWEEN 13634 AND 13653 GROUP BY jour
Avec un index sur "jour" c'est une requête qui ne va pas prendre plus de 0.01s. Attention, si tu utilises InnoDB c'est une toute autre affaire car il n'aime pas beaucoup COUNT(). Sous InnoDB tu ferais mieux de créer un compteur dans une table, que tu mettrais à jour toutes les heures par une tâche cron.

Ah, j'allais oublier. En parlant de tâche cron, pour compter le nombre de téléchargements tu peux aussi utiliser une tâche cron qui lit les logs de ton serveur web et met à jour un compteur quelque part à intervalles plus ou moins réguliers.

Posté : 20 mai 2007, 23:09
par Belisarius
J'ai indexé la colonne `dl_date` et utilisé l'indication BETWEEN ... AND (en plus du COUNT(*) ) et j'ai déjà constaté un gain de 30 % de temps en moins donc je suis déjà très content.

Mon système actuel boucle en fait sur 20 jours, exécutant donc 20 requêtes SQL du même genre que précédemment. Je récupère en fin un tableau du genre array('0'=>'757', '1'=>'2578', ...) ce qui traduis qu'aujourd'hui j'ai eut 757 téléchargements et hier 2578. Je passe ensuite le tableau dans un boucle pour me générer le code XHTML.

Je vais essayer ton système qui m'a l'air très bon car je n'aurais plus qu'une seule requête SQL.

En tout cas déjà un grand merci pour ton aide.

Posté : 22 mai 2007, 19:52
par Belisarius
Ta méthode marche à merveille, c'est encore plus rapide.
Merci mille fois !