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

PHP & Base de données Discussion :

écriture en bdd extraordinairement lente [MySQL]


Sujet :

PHP & Base de données

  1. #1
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 382
    Points : 5 732
    Points
    5 732
    Billets dans le blog
    1
    Par défaut écriture en bdd extraordinairement lente
    Bonjour,

    j'ai un problème de lenteur de mon script, mentionné dans cette discussion https://www.developpez.net/forums/d2124326/php/langage/script-stoppe/ au post #10.

    Le SGBD est MySQL.

    Mon script d'accès à la bdd est le suivant :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     static public function  putInDBLicense($refrefTable, $ref_ppp){
            $save_success = true;
     
            /* pour ne pas avoir à modifier tout le code qui suit    */
            $ref_app = $refrefTable->getref_App();
            $ref_platform = $refrefTable->getref_Platform();
            $ref_country = $refrefTable->getref_Country();
            $ref_location = $refrefTable->getref_Location();
            $ref_company = $refrefTable->getref_Company();
            $ref_BU = $refrefTable->getref_BU();
            $ref_usermanager = $refrefTable->getref_Usermanager();
            $ref_US_user = $refrefTable->getref_US_user();
            $ref_USL_user_license = $refrefTable->getref_USL_user_license();
            $ref_Domain = $refrefTable->getref_Domain();
            $ref_Email = $refrefTable->getref_Email();
            $ref_license = $refrefTable->getref_License();
     
     //insert ou update pour ap_application
            /** @var \ticket_rawsrc\model\license\table\AP_application  $ref_app*/
     
            $save_success &= $ref_app->save(true, $ref_app->getAP_appli_name(), $id_platf, $ref_ppp);  //mise en bdd
     
    // 11 autres écritures en bdd (insert ON DUPLICATE KEY) avec parfois des SELECT avant

    Ce traitement d'écriture en bdd est effectué lors de la lecture d'un fichier CSV. Il est effectué à chaque ligne lue. Le fichier compte 110000 lignes. Au bout de 6 heures, 4500 lignes ont été traitées. Donc une règle de 3 indique que ça prendra 6 jours (6*110000/4500/24 =6,1)
    Comment puis-je optimiser ça ?
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  2. #2
    Expert éminent
    Avatar de Séb.
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    5 098
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 098
    Points : 8 207
    Points
    8 207
    Billets dans le blog
    17
    Par défaut
    C'est dur de te répondre, on ne sait pas ce qui se cache derrière toutes ces méthodes et ni à quoi ressemblent tes UPDATE/INSERT.

    Tu as posé des chronos un peu partout pour voir où ça ralentit ?
    Un problème exposé clairement est déjà à moitié résolu
    Keep It Smart and Simple

  3. #3
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 382
    Points : 5 732
    Points
    5 732
    Billets dans le blog
    1
    Par défaut
    Merci de me répondre. J'ai réalisé après coup qu'il manquait des informations.

    Je les donnerai plus tard car il y a un problème de mesure du temps. J'ai fait un essai plus simple : dans la méthode putInDBLicense, on met que les getters mais pas les écritures :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    static public function  putInDBLicense($refrefTable, $ref_ppp){
            $save_success = true;
     
            /* pour ne pas avoir à modifier tout le code qui suit    */
            /** @var \ticket_rawsrc\model\RefTableLicense  $refrefTable */
            $ref_app = $refrefTable->getref_App();
            $ref_platform = $refrefTable->getref_Platform();
            $ref_country = $refrefTable->getref_Country();
            $ref_location = $refrefTable->getref_Location();
            $ref_company = $refrefTable->getref_Company();
            $ref_BU = $refrefTable->getref_BU();
            $ref_usermanager = $refrefTable->getref_Usermanager();
            $ref_US_user = $refrefTable->getref_US_user();
            $ref_USL_user_license = $refrefTable->getref_USL_user_license();
            $ref_Domain = $refrefTable->getref_Domain();
            $ref_Email = $refrefTable->getref_Email();
            $ref_license = $refrefTable->getref_License();
     
     
        //insert ou update pour pl_platform
         /*   /** @var \ticket_rawsrc\model\license\table\PL_platform  $ref_platform
     
          /*  $save_success &= $ref_platform->save($ref_ppp)
          ... */
    rien que ça, c'est hyper long. Au lieu d'être quasi-instantané, les 110000 appels à la méthode, ça prend au moins 10 minutes.

    Citation Envoyé par Séb. Voir le message
    Tu as posé des chronos un peu partout pour voir où ça ralentit ?
    Honnêtement, je l'avais pas fait car retenu (par erreur) que c'était pas fiable ; en fait, j'ai confondu mesure de temps et mesure de consommation de mémoire, à cause de (du 03/12...)
    Citation Envoyé par CosmoKnacki Voir le message
    Les bizarreries que tu constates à propos de la mémoire sont dues à la manière dont PHP alloue de la mémoire pour les tableaux. Cette quantité allouée est toujours une puissance de 2.

    Prenons un exemple bidon (pour ce qui est des nombres): un tableau stocke des données qui nécessite 600 octets, PHP allouera donc 1024 (2 puissance 10) octets pour le tableau, ce qui en proportion représente une perte énorme. Pourquoi fait-il ça? Pour ne pas avoir à allouer de la mémoire toutes les 5 minutes, c'est un dilemme entre vitesse et mémoire nécessaire. Si le tableau venait à grossir au delà de 1024 octet, PHP allouera de nouveau de la mémoire et passera à la puissance de 2 supérieure, soit 2048 (2 puissance 11).

    C'est la raison pour laquelle tu ne constates pas de changement d'occupation de la mémoire alors que ton tableau grossit. PHP utilise la mémoire qui a déjà été allouée au tableau.
    et de ma très mauvaise mémoire (il faut faire avec mais sacré boulet ).

    Je l'ai donc fait sur l'essai simple mentionné ci-dessus et la mesure de mémoire semble fausse, donc merci de me dire quel est le problème :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
                $debut = microtime(true);
                while (($line_csv = fgetcsv(CSVParser::getHandle(), $buffer, CSVParser::getSeparator(),
                    CSVParser::getEnclosure(),"")) !== false) {
     
                    code de la boucle
     
                    if ($nb_line >= 50000) break; //afin de pas planter à la fin
     
                } //fin de la boucle
                CSVImport::commit(); //on fait le commit en fin de boucle
     
                $fin = microtime(true);
                $temps = 1000*($fin - $debut);
                //Afficher le temps d'exécution
                $temps_de_chargement = number_format($temps, 3);
                echo "boucle exécutée en " . $temps_de_chargement . " msec";
    Ca dure au moins 10 minutes mais ça me dit
    boucle exécutée en 137,107.223 msec
    C'est quoi mon bug ?
    A demain
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  4. #4
    Expert éminent
    Avatar de Séb.
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    5 098
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 098
    Points : 8 207
    Points
    8 207
    Billets dans le blog
    17
    Par défaut
    rien que ça, c'est hyper long
    Il se cache quoi derrière tous es appels de $refrefTable ? Un SELECT à chaque fois ?

    Ca dure au moins 10 minutes mais ça me dit
    Ne complique pas les choses avec des conversions en millisecondes, Ton problème est de l'ordre de la minute/heure, pas de la milliseconde
    Tu exécutes ton script via le navigateur ou en ligne de commandes ?
    Fais un exit() après l'affichage du chrono au cas où autre chose exécuté APRÈS viendrait tout fausser.
    Un problème exposé clairement est déjà à moitié résolu
    Keep It Smart and Simple

  5. #5
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 382
    Points : 5 732
    Points
    5 732
    Billets dans le blog
    1
    Par défaut
    Merci pour ta réponse nocturne et ne pas m'être relevé en pleine nuit pour répondre

    Il se cache quoi derrière tous es appels de $refrefTable ? Un SELECT à chaque fois ?
    Pas de SELECT. Voici le code :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    switch (CSVParser::getCSVType())
                {
     
                    case "license":
     
                        // analyses
                        self::createLicensesObjects();
     
                        $this->errors = Record::analyze_license($this->refTableLicense);
                        //on effectue les analyses. Si une
                        // erreur est détectée, on renseigne la chaîne des erreurs ($this->errors)
                        if (Record::getLastError() == "no error")
                        {
                            CSVImport::putInDBLicense($this->refTableLicense,
                                $this->refPPP);
                        }
                   ....

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
        private function remove_utf8_bom_and_semicolon($text)
            {
                $text = preg_replace('~^\N{U+FEFF}~u', '', $text);
                $text = str_replace(';','',$text);
                return $text;
            }
     
        private function createLicensesObjects()
        {
            $tab = [];
            foreach ($this->data as $key => $value)
            {
                $tab[self::remove_utf8_bom_and_semicolon($key)] = self::remove_utf8_bom_and_semicolon($value);
            }
            $this->data = $tab;
     
            $this->ref_App = new AP_application(($this->data)['sesaid'], $this->data['applicationname']);
     
           //en tout, création de 12 objets mais y a que des affectations de variables
     
        $this->refTableLicense
            = new RefTableLicense;
     
        $this->refTableLicense->setRef_License($this->ref_App,
            $this->ref_Platform,
            $this->ref_Country,
            $this->ref_Location,
            $this->ref_Company,
            $this->ref_BU,
            $this->ref_Usermanager,
            $this->ref_User,
            $this->ref_USL_user_license,
            $this->ref_Domain,
            $this->ref_Mail,
            $this->ref_License);
        }
     
    public function setRef_License( $ref_app,
                                        $ref_platform,
                                        $ref_country,
                                        $ref_location,
                                        $ref_Company,
                                        $ref_BU,
                                        $ref_usermanager,
                                        $ref_US_user,
                                        $ref_USL_user_license,
                                        $ref_Domain,
                                        $ref_Email,
                                        $ref_license)
        {
            $this->ref_App = $ref_app;
            $this->ref_Platform = $ref_platform;
            $this->ref_Country = $ref_country;
            $this->ref_Location = $ref_location;
            $this->ref_Company = $ref_Company;
            $this->ref_BU = $ref_BU;
            $this->ref_Usermanager = $ref_usermanager;
            $this->ref_US_user = $ref_US_user;
            $this->ref_USL_user_license = $ref_USL_user_license;
            $this->ref_Domain = $ref_Domain;
            $this->ref_Email = $ref_Email;
            $this->ref_License = $ref_license;
        }
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  6. #6
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 691
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 691
    Points : 20 222
    Points
    20 222
    Par défaut
    Avant de partir dans tous les sens :

    - Fait un fichier CSV de 10 lignes
    - Mesure le temps de chacun des appels de fonctions majeures
    - Lance le script

    Une fois que tu as identifié la partie qui prend le plus de temps :

    - Supprime les mesures de temps précédentes
    - Ajoute des mesures de temps dans la fonction identifiée comme étant problématique, pour isoler la partie la plus lente.
    - Lance le script

    Si cette partie lente est encore une fonction , répète l'opération précédente , jusqu'à arriver à l'instruction qui est réellement problématique.
    Une fois quetu auras identifié cela , on pourra te conseiller.

    Sans ca , ca me parait difficile d'avoir des remarque pertinentes.

    Si tu veux te faciliter un peu la vie sur la mesure de temps tu peux utiliser cette classe : https://github.com/grunk/Pry/blob/ma...Util/Bench.php

    qui s'utilise de la façon suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    require('bench.php');
     
    $b = new Pry\Util\Bench();
    $b->start();
     
    sleep(1); // Evidemment ce sleep représente le code à mesurer
    $b->add_flag('premier sleep');
     
    sleep(3); // Evidemment ce sleep représente le code à mesurer
    $b->add_flag('2eme sleep');
     
    $b->stop();
    var_dump($b->result());
    Ce qui affiche :
    array (size=3)
    'premier sleep' => float 1.0024399757385
    '2eme sleep' => float 4.0097258090973
    'total' => float 4.0097548961639
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 382
    Points : 5 732
    Points
    5 732
    Billets dans le blog
    1
    Par défaut
    Merci pour la suggestion, grunk.

    Merci aussi de m'avoir indiqué la classe Bench. Je suppose qu'il doit être possible de l'intégrer à Composer. Peut-on m'indiquer comment faire. Voici mon composer.json actuel :
    Code json : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    {
      "name": "schmitt/ticket",
      "description": "tool to manage data extracted from databases (ARM and Remedy)",
      "type": "project",
      "license": "MIT",
      "authors": [
        {
          "name": "Laurent Schmitt",
          "email": "mon_adresse_mail"
        }
      ],
      "keywords": [
        "php"
      ],
      "minimum-stability": "dev",
      "require": {
        "php": ">=8.0",
        "rawsrc/phpecho": "dev-master",
        "rawsrc/pdoplusplus": "dev-master",
        "vlucas/phpdotenv": "5.4.x-dev"
      },
      "autoload": {
        "psr-4": {
          "ticket_rawsrc\\": "src/"
        }
      }
    }
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  8. #8
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 691
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 691
    Points : 20 222
    Points
    20 222
    Par défaut
    Oui ca serait possible , mais ca reviendrait à intégrer tout mon framework , ce qui n'est pas forcément recommandé pour utiliser une seule classe.
    Pour du debug c'est plus simple de simplement copier la classe dans tes sources et de l'inclure comme un simple fichier.

    Après c'était une suggestion , l'utilisation plus basique de microtime() reste une solution tout à fait valable bien qu'un peu fastidieuse.
    Ne te disperse pas et ne te rajoute pas des problèmes
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  9. #9
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 382
    Points : 5 732
    Points
    5 732
    Billets dans le blog
    1
    Par défaut
    C'est fait (code de la classe copié ; classe créée ; appels de la méthode add_flag faits). Pas le temps de continuer l'analyse. Je reprendrai en fin d'après-midi...
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  10. #10
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 382
    Points : 5 732
    Points
    5 732
    Billets dans le blog
    1
    Par défaut
    Tous comptes faits, la mauvaise météo a écourté ma tentative de ski, donc retour aux affaires et...surprise car :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
                // déclencher un chrono
                $b = new Bench();
                $b->start();
                $b->add_flag('avant boucle');
                while (($line_csv = fgetcsv(CSVParser::getHandle(), $buffer, CSVParser::getSeparator(),
                    CSVParser::getEnclosure(),"")) !== false) {
                    $b->add_flag('début boucle');
                    ...
    donne
    cvsimportcontroller 199 mesure du temps
    array(7) {
    ["avant boucle"]=>
    float(1.7881393432617188E-5)
    ["début boucle"]=>
    float(0.021346092224121094)

    ["avant création objets"]=>
    float(0.021407127380371094)
    ["après création objets"]=>
    float(0.0216372013092041)
    ["après analyses"]=>
    float(0.024468183517456055)
    ["après écriture en bdd"]=>
    float(0.024485111236572266)
    ["boucle"]=>
    float(0.02472519874572754)
    ["total"]=>
    float(0.024730205535888672)
    }
    or les 3 méthodes appelées dans la boucle while sont des vrais getters :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public  static function getHeader()
        {
            return self::$header;
        }
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public  static function getSeparator()
        {
            return self::$separator;
        }
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     public  static function getEnclosure()
        {
            $ret = (strlen(self::$enclosure) == 1) ? self::$enclosure : '"';
            return($ret);
        }
    donc presque la totalité du temps semble consommée par l'appel à la fonction fgetcsv. Comme c'est sûrement pas ça, qu'est-ce qui se passe STP ?
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  11. #11
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 691
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 691
    Points : 20 222
    Points
    20 222
    Par défaut
    Je vois rien d'anormal dans ce que tu me montres puisque le temps total d'exécution est de 24ms (0.024s)

    Tu n'as probablement pas vue l'exposant -5 (E-5) sur la première valeur.

    Donc le problème n'est pas ici.
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  12. #12
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 382
    Points : 5 732
    Points
    5 732
    Billets dans le blog
    1
    Par défaut
    Effectivement car si on multiplie 24ms par 110000, ça fait moins d'une heure...Je vais donc chercher ailleurs.
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  13. #13
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 382
    Points : 5 732
    Points
    5 732
    Billets dans le blog
    1
    Par défaut
    Bonjour,
    hier, quand je montrais les mesures de temps, j'avais oublié de décommenter l'écriture en bdd !

    Je l'ai fait, puis refait des mesures de temps avec des fichiers CSV de 5, 10, 20, 100, 200 et 1000 lignes. Pour chacun, je calcule par une règle de 3 le temps qu'il faudrait pour les 110000 lignes et le résultat est surprenant !

    5 lignes : 0,076s -> 0,076*110000/5/60 = 27 minutes
    10 lignes : 0,16s -> 0,16*110000/10/60 = 29 minutes
    20 lignes : 0,48s -> 0,48*110000/20/60 = 44 minutes
    100 lignes : 7,4s -> 7,4*110000/20/60 = 135 minutes
    200 lignes : 38,3s -> 38,3*110000/20/60 = 351 minutes 
    1000 lignes : 1039s -> 1039*110000/20/60 = 1905 minutes = 32 heures !
    
    d'où ça peut venir ?
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  14. #14
    Expert éminent
    Avatar de Séb.
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    5 098
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 098
    Points : 8 207
    Points
    8 207
    Billets dans le blog
    17
    Par défaut
    On n'a pas la moindre idée des vérifs effectuées et de ton schéma de bdd, comment pourrait-on te répondre ?
    Un problème exposé clairement est déjà à moitié résolu
    Keep It Smart and Simple

  15. #15
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 382
    Points : 5 732
    Points
    5 732
    Billets dans le blog
    1
    Par défaut
    Et oui, moi qui te croyais devin...

    Je viens de refaire une mesure en commentant l'écriture en bdd :
    1000 lignes : 1,89 secondes -> 1,89*110000/1000/60 = 3,465 minutes
    
    Ca a quand même bien diminué mais c'est pas terrible.

    Mon idée est d'essayer d'améliorer cette partie puis de tenter d'appliquer les règles d'amélioration au reste du code. OK ?
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  16. #16
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 382
    Points : 5 732
    Points
    5 732
    Billets dans le blog
    1
    Par défaut
    Donc voici le code avec seulement les analyses :

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     switch (CSVParser::getCSVType())
                {
     
                    case "license":
     
                        // analyses
                        self::createLicensesObjects();
     
                        $this->errors = Record::analyze_license($this->refTableLicense);
     
                        //on effectue les analyses. Si une
                        // erreur est détectée, on renseigne la chaîne des erreurs ($this->errors)
                        if (Record::getLastError() == "no error")
                        {
    //                        CSVImport::putInDBLicense($this->refTableLicense,
    //                            $this->refPPP);
                        }
     
                       break;

    getCSVType :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public  static function  ()
        {
            return self::$csv_type;
        }

    self::createLicensesObjects() : cf post #5.

    analyze_license :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     public static function analyze_ticket($refrefTableTicket)
        {
            /* pour ne pas avoir à modifier tout le code qui suit */
            $ref_ticket = $refrefTableTicket->getref_ticket();
            $ref_Pr = $refrefTableTicket->getref_pr();
            $ref_ag = $refrefTableTicket->getref_ag();
            $ref_OZ = $refrefTableTicket->getref_OZ();
            $ref_USS_user_submitter = $refrefTableTicket->getref_USS_user_submitter();
            $ref_USS_user_requester = $refrefTableTicket->getref_USR_user_requester();
            $ref_Country = $refrefTableTicket->getref_Country();
     
            self::$there_is_an_error = false; //init à false
     
            /** @var \ticket_rawsrc\model\ticket\table\PR_product  $ref_Pr */
            if (!$ref_Pr->isValid())
            {
                self::$errors[] = $ref_Pr->error_s();
     
     
                self::$there_is_an_error = true;
            }
     
            // 6 autres appels à la méthode isValid sur d'autres instances d'objet
     
          if (! self::$there_is_an_error)
            {
                self::$errors[] = "no error"; /*si pas d'erreur sur cette ligne, on met une
                ligne "no error" ds le tableau self::$errors */
            }

    méthode isValid pour l'instance $ref_Pr :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    public function isValid():bool
        {
            $error = false;
     
            if ( !self::validString($this->appli_name) )
            {
                $this->errors[] = "For SESA=" . $this->sesaid . " and application=" .  $this->appli_name .
                   ', "' . $this->appli_name . '" (column appli_name) '.$this->accepted_characters;
     
                self::setError($this->sesaid, $this->appli_name, $this->appli_name . '" (column appli_name)'.$this->accepted_characters);
     
                $error = true;
     
            }
     
            if (!$this->isPrdInDB($this->appli_name))
            {
                $this->errors[] = "For SESA=" .
                    $this->sesaid .
                    " and application=" .
                    $this->appli_name .
                    "," .
                    $this->appli_name .
                    " does not exist";
     
                self::setError($this->sesaid, $this->appli_name,
                    $this->appli_name .
                    " does not exist");
     
                $error = true;
            }
     
                if (!$this->getCorrespondantAppliName($this->appli_name))
                {
                    $this->errors[] = "For SESA=" .
                        $this->sesaid .
                        " and application=" .
                        $this->appli_name .
                        "," .
                        $this->appli_name .
                        " has no correspondant application name";
     
                    self::setError($this->sesaid, $this->appli_name,
                        $this->appli_name .
                        " has no correspondant application name");
     
                    $error = true;
                }
     
     
            return !$error;
        }

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     public function validString($string):bool
        {
            $pattern = '#(?xx)\A[A-Za-z0-9_ \p{Han} \- ( ) , Ä Å Á Ë Ė È É Ï Í  Ó Ö  Ü Ū Ú | Ç Č Ć Ļ Ñ Š Ž &  \/ . \h \' "]*\z #u';
     
            $ret2 = preg_match($pattern, $string);
     
            return ($ret2 == 1) ;
        }

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public function setError($sesaid, $appli_name, $error_name) {
            $this->error_s["sesaid"][]=$sesaid;
            $this->error_s["appliname"][]=$appli_name;
            $this->error_s["errorname"][]=$error_name;
        }

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    private function isPrdInDB($prd_name):bool
        {
            $test_prd_name = new PDOPlusPlus();
            $sql =
                "SELECT PR_product_name from `pr_product` where PR_product_name={$test_prd_name($prd_name)}";
            $appli_exists = $test_prd_name->select($sql);
            return(isset($appli_exists[0]['PR_product_name']));
        }

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     private function getCorrespondantAppliName( $name){
     
            $ppp = new PDOPlusPlus();
            $SQL = <<<SQL
    SELECT AP_application_name FROM AP_application;
    SQL;
            $resAppli = $ppp->select($SQL);
     
            $percent = 0;
     
            foreach($resAppli AS $one_appli) {
                $sim =  similar_text($name, $one_appli['AP_application_name'], $percent);
                if ($percent > 50) return true;
            }
     
            return ( false);
     
        }

    T'ai-je donné suffisamment d'info ?
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  17. #17
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 691
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 691
    Points : 20 222
    Points
    20 222
    Par défaut
    Est tu certains que c'est ton insertion qui est longue et pas plutôt ta fonction isPrdInDB() qui prend de plus en plus de temps au fur et à mesure que tu ajoute des lignes ?

    En règle générale une insertion prend toujours le même temps quelque soit le nombre d'entrée dans la base.
    En revanche un select peut être de plus en plus long si on à pas défini les bons index sur la table.

    Pour t'en assurer tu peux lancer ta requête en y ajoutant le mot clé EXPLAIN dans phpmyadmin (ou tout autre outil) et regarder la valeurs "rows".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    EXPLAIN SELECT PR_product_name from `pr_product` where PR_product_name={$test_prd_name($prd_name)}
    Dans le resultat retourné , si la valeur du champs "rows" est équivalent au nombre de ligne dans ta base ca veux dire que la bdd doit parcourir toute les lignes pour te retourner un résultat ce qui est évidemment problématique pour les performances et va en se dégradant au fur et a mesure que la table se remplie
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  18. #18
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 382
    Points : 5 732
    Points
    5 732
    Billets dans le blog
    1
    Par défaut
    Je mets un certain temps à répondre (j'avais mis ce sujet de côté).
    Selon moi, le temps d'exécution de la fonction isPrdInDB n'est pas lié au nombre de lignes traitées sachant que la table pr_product a une taille fixe et ne se remplie pas au fur et à mesure du traitement. Néanmoins, pour observer l'influence de l'écriture en bdd, j'ai écrit ceci :

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     self::createLicensesObjects();
     
    //$this->errors = Record::analyze_license($this->refTableLicense);
     
    //on effectue les analyses. Si une
    // erreur est détectée, on renseigne la chaîne des erreurs ($this->errors)
    $debug = false;
    if ((Record::getLastError() == "no error") || ($debug))
    {
        CSVImport::putInDBLicense($this->refTableLicense,
            $this->refPPP);
    }

    Si $debug est à false, c'est quasi instantané alors que si il est à true, ça met des plombes. Et la méthode isPrdInDB n'est pas appelée vu que j'ai commenté toutes les analyses.
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

  19. #19
    Expert éminent
    Avatar de Séb.
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    5 098
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 098
    Points : 8 207
    Points
    8 207
    Billets dans le blog
    17
    Par défaut
    Donc c'est le INSERT, et/ou la classe PDOPlusPlus utilisée, qui pose problème
    D'une manière générale c'est normal qu'un INSERT soit de plus en plus long si le poids de la table augmente, surtout si tu as beaucoup d'INDEX à màj
    Par contre l'ordre de grandeur exponentiel de la dégradation me semble anormal

    Quel est ton serveur de BdD ? MariaDB ? MySQL ? Autre ?
    Dans combien de tables fais-tu du INSERT ? Tu peux nous donner le schéma des tables et les INDEX posés ?

    Encore une fois, je pense qu'il faut que tu simplifies ton code et que tu en reprennes la maitrise

    PDOPlusPlus, l'intérêt ne me semble pas flagrant, je vois que la classe fait une préparation de la requête
    Si avant chaque INSERT tu as un PREPARE, c'est la cata
    Mais bon, je ne sais pas comment c'est géré par la classe

    Simplifie, passe par PDO directement, pour voir
    Si tu as toujours des lenteurs fait des injections par paquets de 5000 avec des transactions ou en construisant un INSERT ... VALUES (...), (...), (...)
    Si tu as toujours des lenteurs prépare un fichier TSV ($separator = "\t", $enclosure = '') et en sortie de boucle importe-le avec LOAD DATA, il n'y pas plus rapide
    Un problème exposé clairement est déjà à moitié résolu
    Keep It Smart and Simple

  20. #20
    Expert confirmé
    Avatar de laurentSc
    Homme Profil pro
    Webmaster débutant perpétuel !
    Inscrit en
    Octobre 2006
    Messages
    10 382
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Webmaster débutant perpétuel !
    Secteur : Industrie

    Informations forums :
    Inscription : Octobre 2006
    Messages : 10 382
    Points : 5 732
    Points
    5 732
    Billets dans le blog
    1
    Par défaut
    Merci pour ta réponse.
    Le SGBD est MySQL et j'écris dans 12 tables.

    J'ai bien un schéma mais il couvre toute l'application et décrit donc 16 tables, dont certaines ne sont pas impliquées ici. Quand tu demandes les index posés, s'agit-il bien des clés uniques et des clés étrangères ? (elles sont nombreuses).

    Je pense me tourner vers l'auteur de la classe PDOPlusPlus qui saura dire si la lenteur peut venir de là.
    Il vaut mieux viser la perfection et la manquer que viser l'imperfection et l'atteindre. - Bertrand Russell

    Si la discussion est résolue, merci de cliquer sur le bouton

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 3 123 DernièreDernière

Discussions similaires

  1. [MySQL] Erreur pour écriture dans BDD
    Par laissaAnn dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 03/05/2013, 15h47
  2. Accès en écriture à la BdD impossible
    Par tssr2008 dans le forum WebDev
    Réponses: 3
    Dernier message: 20/06/2008, 00h48
  3. Réponses: 5
    Dernier message: 18/07/2007, 11h38
  4. Réponses: 1
    Dernier message: 24/10/2006, 12h10
  5. Meilleur méthode d'écriture en bdd - optimisation
    Par maximenet dans le forum SQL Procédural
    Réponses: 2
    Dernier message: 14/09/2006, 12h15

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