Accelérer un script utilisant fopen & du mysql

Répondre
limace2000
le 19/08/2009 à 10:32
limace2000
Bonjour

Je suis nouveau sur ce forum et j'éspére que vous allez pouvoir m'aider !!!!

J'utilise en local un script de lecture d'un fichier texte pour l'incorporer dans une base mysql.

Je lis donc mon fichier texte en cherchant les noms de colonnes et les données (séparé par des :) et je recherche également les "@" qui séparents mes nouvelles lignes dans mon tableau. C'est clair ?

Voici un extrait de mon fichier (qui fait 40 000 lignes):
$FILE:
DAC_Clic_Phase1: 0
$FILE:
OriginalModTime: 03/10/2006 09:47:44
DAC_UNID: 6AF1EDDAF236F98BC1257102005982D5
DAC_Sce: 172
DAC_Quant: 2
DAC_Serie: Unitaire
DAC_Code_Site: F04
$Revisions: 26/01/2006 17:28:01,26/01/2006

@
$FILE:
DAC_Clic_Phase1: 0
$FILE:
OriginalModTime: 05/03/2009 16:46:44
DAC_UNID: 046674D672CE4EB5C12571020047B2A5
PH1_Visibilite: Non
$Revisions: 26/01/2006 14:07:06,26/01/2006 14:07:07,26/01/2006
voir data


@
$FILE:
DAC_Clic_Phase1: 0
OriginalModTime: 27/11/2006 18:14:49
DAC_UNID: 39DB170F75E269CFC125710100511222
DAC_Sce: 015


Et voici mon code PHP:
<?php
set_time_limit (60000000000000);
$handle = fopen('file.txt', 'r');

if ($handle) {

$link = mysql_connect('localhost', '***', '***') or die('Impossible de se connecter : ' . mysql_error());
mysql_select_db('***') or die('Impossible de sélectionner la base de données');
mysql_query("LOCK TABLES *** WRITE");

$id=1;

//insertion du 1er enregistrement
$sql = "INSERT INTO `***` (`id`) VALUES ('$id')";
$requete = mysql_query ($sql);


while (!feof($handle)) {
$buffer = fgets($handle, 4096);

if (substr($buffer,0,1) =="@"){
// Si c'est une nouvelle ligne
$drapeau=0;
$id++;
$sql = "INSERT INTO `***` (`id`) VALUES ('$id')";
$requete = mysql_query ($sql);
}
else
{
//extraction des données
$entete = trim(substr($buffer,0,strpos($buffer, ":")));
$corps = trim(substr($buffer,strpos($buffer, ":")+1));

if ($entete == "$Revisions")$drapeau=1;
if ($drapeau == 1){
$entete="$Revisions";
$corps=$buffer;
}

// Traitement des lignes sans intitulé de colonnes

if ($entete==''){
$entete=$entete_old;
$corps=$corps_old.$corps;
}

$entete_old=$entete;
$corps_old=$corps;

if ($corps<>"" or $corps<>" " ){
// Connexion au serveur mysql
$sql = "UPDATE `***` SET $entete='$corps' where id=$id";
$requete = mysql_query ($sql);
if (!$requete) {
// Si l'insertion n'a pas marché ca veux dire que la colonne n'existe pas. On la cré et on relance la requete
$sql = "ALTER TABLE `***` ADD `$entete` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL";
$requete = mysql_query ($sql);
$sql = "UPDATE *** SET `$entete`='$corps' where id=$id";
$requete = mysql_query ($sql);
}
}
}
mysql_query("UNLOCK TABLES");
}
fclose($handle);
}
?>


Ma probléme et que ce script marche rapidement au début mais peu a peu ca ralentie enormémént !!!!

D'où viens ce ralentissement ???
la limace
LA GLOBULE
le 19/08/2009 à 18:57
LA GLOBULE
PHP est réputé être une tortue en traitement de fichier (perl fait 1000 fois mieux), mais a priori, ton script ne "charge pas" la machine (je parle la du processus PHP (ou apache) et non le processus MySQL) au fur et à mesure qu'il s'éxécute.

Ce qui pose problème, à mon avis, c'est ton SQL et non la lecture / le traitement du fichier texte.
Tes ALTER TABLE me font peur. En effet, tu ajoutes de nombreux champs de type TEXT qui sont réputés pour alourdir considérablement les operations de selections / modifications (il vaut mieux travailler sur une petite table avec des petits int représentant des clefs et d'avoir des tables de correspondances avec juste la clé et le champ TEXT).

Pour t'en convaincre, tu peux bencher des parties de ton code :
- soit en utilisant l'extension xdebug de PHP
- soit en utilisant tout simplement la fonction microtime qui te permettra de calculer le temps d'execution de chaque partie de ton script
LupusMic
le 20/08/2009 à 03:11
LupusMic
Plusieurs commentaires à propos de ton code.

60000000000000 n'est pas un nombre entier que PHP peut représenter dans un entier (maximum : 2^32 - 1).
Habituellement, lorsqu'une fonction règle un paramètre, lui fournir 0 signifie souvent quil y a désactivation du contrôle de ressource. C'est confirmé par la doc de set_time_limit.

Utiliser die c'est mal. Il faut gérer l'erreur, et non pas tuer froidement le script.

Il y a un trou de sécurité dans la construction de ta requête. il faut utiliser mysql_real_escape_string pour préparer les informations fournies.

Il manque un espace de séparation dans le update de la ligne 53.

Il faut que tu apprenne les tables de vérité, et l'algèbre booléenne par extension.

Essaye d'indenter correctement ton code. Pour cela, utilises un éditeur de texte plus adapté tel que Vim ou emacs, plutôt que Notepad.

Lorsque tu as un if qui est suivit d'un statement composé d'un seul statement, renvoie à la ligne ce statement.
Développeur récurrent, procédural et relationnel. Caustique soupe-au-lait.
limace2000
le 21/08/2009 à 08:59
limace2000
Bonjour

Merci pour les conseils.
- Pour les champs de type TEXT : Oui j'avais mis ca au début ne connaissant pas trop le type de données qui allé tomber mais maintenant je peux ajuster ...

- Pour la faille de sécurité c'est pas bien grave puisque je travail en locale.

- Les tables de vérité, et l'algèbre booléenne : Oui je connais, j'ai fais de l'électronique et je vois bien que ça pourrai me servir mais j'ai du mal a voir où et comment !!!!

Je viens de télécharger VIM :-)
J'applique les modifs et je vous tiens informé
Merci
la limace
LupusMic
le 21/08/2009 à 22:23
LupusMic
Au-delà du type de données, il ne faut pas oublier que rajouter une colonne est une opération lourde. Par exemple, si tu as 100 000 tuples dans ta table, ajouter une colonne signifie que 100 000 lignes seront modifiées.

Ce n'est pas d'ailleurs la taille de ton fichier ? :D

Relis la réponse de La Globule. Il te montre la voie vers laquelle tu devrais te diriger.

J'ai parlé de l'algèbre booléenne et des tables devérité parce que la condition de la ligne 50 :
<?php if ($corps<>"" or $corps<>" " )

est toujours vrai.

Je pense que tu voulais plutôt écrire
<?php if (!($corps == "" || $corps == " " ))

ou
<?php if ($corps <> "" && $corps <> " ")
Développeur récurrent, procédural et relationnel. Caustique soupe-au-lait.
Répondre

Ecrire un message

Votre message vient d'être créé avec succès.
LoadingChargement en cours