IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Votre avis sur mon raisonnement. [PHP 5.0]


Sujet :

Langage PHP

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2008
    Messages
    155
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 155
    Par défaut Votre avis sur mon raisonnement.
    Bonjour,

    Je travaille depuis plusieurs jours sur un script très gourmand en temps et en mémoire.

    Ce script parse des flux xml et enregistre le flux dans une base de données mysql ou bien met la base de données à jour.

    pour les petits flux ça marche pas mal quelques soit la procédure.

    J'ai par contre des flux contenant 70 000 et 140 000 articles et c'est la que ça se complique.

    Par exemple le fichier xml contenant 70 000 articles fait 65MB et l'exécution du script actuel qui met à jour la base de données met 2h47mn a en voir le bout en local avec wamp. pour le deuxième je n'ai pas encore essayé.

    Mais ça marche, ce qui est déjà pas mal, il n'y a plus qu'a améliorer tous cela.

    Je voulais donc avoir votre opinion sur les différentes étapes de mon script.

    1er Solution:
    - Je vais chercher la référence unique de tous les articles qui existe déjà dans la BDD pour ce flux et je les mets dans un tableau $articles_existant.
    - Je crée deux tableau vide $nouveau_art et $modif_art.
    - je parse le flux avec sax donc en évènementielle qui fonctionne très bien même avec les gros fichiers.
    - Dans mon parseur de flux, a chaque nouvel article je fais un foreach sur $articles_existant afin de voir si cet article est déja présent dans la base.
    - Si l'article est déja présent dans la base, je le met dans $modif_art et s'il n'est pas présent dans $nouveau_art.
    - Une fois tous le flux parser, j'ajoute tous les articles de $nouveau_art dans la base et je modifie tous les articles de $modif_art.
    - Fin du script.
    Probléme
    - pour les gros flux j'ai le message d'erreur comme quoi la mémoire est insuffisante, je ne sais plus le terme exact, j'ai pourtant 128M de mémoire dispo. Mais comme le flux fait déja 65MB + le tableau des articles existants + quelques fioritures dont je n'ai pas parlé ci-dessus. ca plante.


    2éme Solution:
    - Je vais chercher la référence unique de tous les articles qui existe déjà dans la BDD pour ce flux et je les mets dans un tableau $articles_existant.
    - Je crée deux tableau vide $nouveau_art et $modif_art.
    - je parse le flux avec sax donc en évènementielle qui fonctionne très bien même avec les gros fichiers.
    - Dans mon parseur de flux, a chaque nouvel article je fais un foreach sur $articles_existant afin de voir si cet article est déja présent dans la base.
    - Si l'article est déja présent dans la base, je le met dans $modif_art et s'il n'est pas présent dans $nouveau_art.
    - Dans mon parseur, je compte le nombre d'articles parser.($nb)
    - Tous les 5000 articles parser, j'ajoute tous les articles de $nouveau_art dans la base et je modifie tous les articles de $modif_art.
    - Je vide mes 2 tableaux $nouveau_art et $modif_art pour libérer de la mémoire et je continu par paquet de 5000.
    - Fin du script.
    Probléme
    - Ca plante, et je ne sais pas pourquoi. une fois il me fait 1 seule boucle (5000 articles), une fois 3 (15 000) ou autre et pas forcément des boucles complète !!! j'ai l'impression que le temps d'enregistrer les données dans la BDD, il perd le flux!!! Bizarre

    3éme Solution:
    - Je crée une table par exemple:table2 ou je vais enregistrer le flux et faire ma mise à jour dans un deuxième temps.
    - Je parse tous le flux et je l'enregistre dans table2.
    - je fais une requête avec jointure pour ressortir les articles qui existe dans table2 et pas dans table. ce qui me donne les nouveaux articles.
    - Je vais chercher tous les nouveaux articles de table2 et je les ajoutes dans table.
    - Je supprime les nouveaux articles de table2.
    - Je vais chercher tous ce qui reste dans table2 et je modifie les articles dans table.
    - Fin du script.
    Probléme
    - Ca marche en 2h47mn pour le flux de 65MB

    Qu'en pensez vous ?
    Auriez-vous un raisonnement différents ?
    Un retour d'expérience peut-être.

    Merci d'avance.

  2. #2
    mon_nom_est_personne
    Invité(e)
    Par défaut
    perso j'essayerais jamais de parser 65mb de text d'un coup et d'inserer dans une db. Car quoi qu'il arrive 70000 noeuds c'est beaucoup. Donc quoi qu'il en soit ton script prendras du temps. je travaillerais plutot de la maniere suivante:
    - je stream le contenue du xml comme ca on a pas 65mb a mettre en memoire
    (cf. http://jp.php.net/manual/fr/ref.stream.php). Ca devrait alleger ta memoire d'autant plus qu'il est moins gourmand de parser 1 noeud 70000 que 70000 noeuds en 1 fois. Ensuite la sql de mise en base sera la meme. donc un coup de pdo->prepare pour cacher la sql afin d'aller plus vite sur les sql.

  3. #3
    Membre Expert

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Par défaut
    Je n'ai jamais travaillé sur un projet perso avec une volumétrie pareille mais voici quelques pistes :

    * Si ce n'est pas deja fait, met des INSERT DELAYED et des UPDATE LOW_PRIORITY dans tes requetes
    *mysql_unbuffered_query et/ou mysql_free_result
    * Les fichiers XML sont souvent (trop) verbeux. Pourquoi ne pas les passer par XSLT ou autre (eventuellement dans un autre langage) avant de les parser en php pour les alleger un peu ?
    * Dans le meme ordre d'idée, il est peut etre possible de "découper" l'XML source pour avoir des fichiers plus petits a traiter
    * "foreach sur $articles_existant" => in_array ?

    Dans tout les cas, je pense qu'il faut que tu fasse quelque chose qui ressemble a ta solution 2... pour la simple raison que si tes fichiers grossissent encore, le découpage et le traitement par lot sera la seule alternative raisonnable.

  4. #4
    Rédacteur
    Avatar de marcha
    Homme Profil pro
    Développeur Web
    Inscrit en
    Décembre 2003
    Messages
    1 571
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 571
    Par défaut
    Salut,

    A mon avis ton soucis vient de l'utilisation des tableaux $nouveau_art,
    $modif_art et $articles_existant.

    Ne peux-tu pas simplement tenter un UPDATE pour chaque article et
    si l'article n'a pas été updaté, faire un INSERT ? et ne plus utiliser
    ces trois tableaux temporaires ?

  5. #5
    Membre Expert

    Homme Profil pro
    Inscrit en
    Janvier 2004
    Messages
    1 249
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 1 249
    Par défaut
    Autre idée :

    Pour les insert, pourquoi ne pas générer un fichier csv (avec XSLT ou en le créant via le script dans un fichier streamé) et utiliser LOAD DATA INFILE ?
    http://dev.mysql.com/doc/refman/5.0/...ert-speed.html

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2008
    Messages
    155
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 155
    Par défaut
    Merci a tous pour vos réponse.

    J'avais un problème au niveau de mes index dans ma BDD.

    L'étape: "je fais une requête avec jointure pour ressortir les articles qui existe dans table2 et pas dans table. ce qui me donne les nouveaux articles." prenait environs 1heure à elle seule.

    Avec de bon index la solution 3 s'exécute en 4mn 50s.

    Je considère donc mon problème comme résolu.

    Vos réponses me servirons à améliorer mon script, car si je peux encore gagner du temps, je le ferais.

    Merci et bonne soirée.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Votre avis sur mon MacOs version Web
    Par arnolem dans le forum Mon site
    Réponses: 10
    Dernier message: 14/08/2006, 11h32
  2. Votre avis sur mon site
    Par bibom dans le forum Mon site
    Réponses: 18
    Dernier message: 28/07/2006, 17h03
  3. Réponses: 5
    Dernier message: 28/07/2006, 08h07
  4. votre avis sur mon premier site
    Par hajmainou dans le forum Mon site
    Réponses: 6
    Dernier message: 21/06/2006, 00h59
  5. [Mémoire Licence] Votre avis sur mon titre
    Par soad029 dans le forum Stages
    Réponses: 8
    Dernier message: 23/05/2006, 19h21

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo