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 :

performances pour sauvegarder le résultat d'une grosse requête


Sujet :

PHP & Base de données

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2013
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2013
    Messages : 40
    Par défaut performances pour sauvegarder le résultat d'une grosse requête
    Bonjour a tous,

    Je dois sauvegarder dans un fichier le résultat d'un requête mySql qui me renvoie 3 millions de lignes.
    Voici le code que j'utilise:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    $fh = fopen($csv_files[$i], 'w');
    $sql = "SELECT UNIX_TIMESTAMP(`TIME2`) AS the_time2, `speed` AS speed, `friction` AS friction FROM `$theMnemo` WHERE `time` >= '$starts[$i]' AND `time` <= '$stops[$i]' AND NOT `speed` = 0 AND NOT `friction` = 0";
    $req = mysql_unbuffered_query($sql);
    while( $data = mysql_fetch_assoc($req) )
    {
    	fwrite($fh, $data['the_time2']."\t".$data['speed']."\t".$data['friction']."\n");
    	$nb_points_array[$i]++;
    }
    fclose($fh);
    Cela fonctionne très bien, mais ça prend presque une minute. La question est simple: avez vous une idée pour améliorer les performances?

    Etant sous linux, j'ai essayé d’écrire le fichier dans la RAM (tmpfs) plutôt que sur le disque mais ça ne change rien.
    Pendant que le code PHP tourne, le processus MySQL a le statut "Sending data".
    Les serveurs sql et http/php sont sur la même machine.


    Merci d'avance!!!

  2. #2
    Modératrice
    Avatar de Celira
    Femme Profil pro
    Développeuse PHP/Java
    Inscrit en
    Avril 2007
    Messages
    8 633
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeuse PHP/Java
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2007
    Messages : 8 633
    Par défaut
    A titre indicatif, sur mon poste de dev en local, générer un fichier texte de 3 millions de lignes me prend 30 secondes (avec une boucle for qui écrit "Ligne n°$i") Tu peux éventuellement tester le temps que ça prend sur ton serveur.

    Donc, basiquement, on a deux pistes :
    - la requête proprement dite : ça c'est du ressort de la gestion de la base (indexes, tout ça...)
    - la lecture des données côté PHP et l'écriture du fichier. En dehors du fait que tu utilises une fonction de l'API mysql (qui est supprimée en PHP 7 et qui va te poser problème à plus ou moins long terme), je ne suis pas sûre qu'on puisse faire mieux
    Modératrice PHP
    Aucun navigateur ne propose d'extension boule-de-cristal : postez votre code et vos messages d'erreurs. (Rappel : "ça ne marche pas" n'est pas un message d'erreur)
    Cherchez un peu avant poser votre question : Cours et Tutoriels PHP - FAQ PHP - PDO une soupe et au lit !.

    Affichez votre code en couleurs : [CODE=php][/CODE] (bouton # de l'éditeur) et [C=php][/C]

  3. #3
    Expert confirmé
    Avatar de rawsrc
    Homme Profil pro
    Dev indep
    Inscrit en
    Mars 2004
    Messages
    6 142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Dev indep

    Informations forums :
    Inscription : Mars 2004
    Messages : 6 142
    Billets dans le blog
    12
    Par défaut
    Salut,

    je pense que c'est optimisable :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $sql = <<<sql
    SELECT CONCAT(UNIX_TIMESTAMP(`TIME2`), "\t", `speed`, "\t", `friction`, "\n") AS txt
      FROM `{$theMnemo}` 
     WHERE `time` >= '{$starts[$i]]' 
           AND `time` <= '{$stops[$i]}' 
           AND NOT `speed` = 0 
           AND NOT `friction` = 0
    sql;
    $req  = mysql_unbuffered_query($sql);
    $data = [];
    while ($row = mysql_fetch_assoc($req)) {
        $data[] = $row['txt'];
        $nb_points_array[$i]++;
    }
    file_put_content($csv_files[$i], implode('', $data));

  4. #4
    Membre averti
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2013
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2013
    Messages : 40
    Par défaut
    Citation Envoyé par Celira Voir le message
    A titre indicatif, sur mon poste de dev en local, générer un fichier texte de 3 millions de lignes me prend 30 secondes (avec une boucle for qui écrit "Ligne n°$i") Tu peux éventuellement tester le temps que ça prend sur ton serveur.
    Voici mon petit code de test:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <?php
    $time_1 = microtime(true);
    $fh = fopen('test_3_million', 'w');
    for ($i=0; $i<3000000; $i++)
    {
    	fwrite($fh, "Lign $i\n");
    }
    fclose($fh);
    $time_2 = microtime(true);
    echo "Duration: ".round(($time_2-$time_1)*1, 3)." seconds";
    ?>
    Quand je crée le fichier sur le disque local: 7 secondes.
    Quand je crée le fichier sur un disque virtuel monte dans la ram: 5 secondes.
    Pour info le serveur est virtualise. Son hote VMware est un gros bébé qui virtualise dans les 150 ordinateurs (serveurs et postes clients).


    Citation Envoyé par Celira Voir le message
    En dehors du fait que tu utilises une fonction de l'API mysql
    De quelle fonction parles tu? Je suis toujours preneur d'une amélioration


    En utilisant le code de rawsrc:
    Code : 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
    <?php
    include("config.php");
    $db = mysql_connect($db_host, $db_user, $db_passwrod);
     
    $time_1 = microtime(true);
    $sql = <<<sql
    SELECT CONCAT(UNIX_TIMESTAMP(`TIME2`), "\t", `speed`, "\t", `friction`, "\n") AS txt
     FROM `M083`.`RW4_05`
     WHERE `time` >= '2018-01-01 00:00:00'
           AND `time` <= '2019-10-04 00:00:00'
           AND NOT `speed` = 0 
           AND NOT `friction` = 0
    sql;
    $req  = mysql_unbuffered_query($sql);
    $data = [];
    while ($row = mysql_fetch_assoc($req)) {
        $data[] = $row['txt'];
    }
    file_put_contents('test_1', implode('', $data));
    $time_2 = microtime(true);
    echo "Duration test 1: ".round(($time_2-$time_1)*1, 3)." seconds\n<br />";
     
     
    $time_1 = microtime(true);
    $fh = fopen('test_2', 'w');
    $sql = "SELECT UNIX_TIMESTAMP(`TIME2`) AS the_time2,
    	`speed` AS speed,
    	`friction` AS friction
    	FROM `M083`.`RW4_05`
    	WHERE `time` >= '2018-01-01 00:00:00'
    	AND `time` <= '2019-10-04 00:00:00'
    	AND NOT `speed` = 0
    	AND NOT `friction` = 0";
    $req = mysql_unbuffered_query($sql);
    while( $data = mysql_fetch_assoc($req) )
    {
    	fwrite($fh, $data['the_time2']."\t".$data['speed']."\t".$data['friction']."\n");
    }
    fclose($fh);
    $time_2 = microtime(true);
    echo "Duration test 2: ".round(($time_2-$time_1)*1, 3)." seconds\n<br />";
     
    mysql_close();
     
    ?>
    Resultat:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Duration test 1: 47.614 seconds 
    Duration test 2: 47.55 seconds
    Donc c'est kifkif mais bien tenté

  5. #5
    Expert confirmé
    Avatar de mathieu
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    10 672
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 10 672
    Par défaut
    Citation Envoyé par ben500fr Voir le message
    De quelle fonction parles tu? Je suis toujours preneur d'une amélioration
    vous pouvez trouver plus d'informations sur la remarque de Celira sur la page suivante :
    https://www.php.net/manual/fr/intro.mysql.php

    en ce qui concerne votre question initiale je ne suis pas sur d'avoir bien compris.
    vous voulez économiser le temps de calcul de la requête en stockant le résultat dans un genre de fichier de cache ?

  6. #6
    Membre averti
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2013
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2013
    Messages : 40
    Par défaut
    Citation Envoyé par mathieu Voir le message
    vous pouvez trouver plus d'informations sur la remarque de Celira sur la page suivante :
    https://www.php.net/manual/fr/intro.mysql.php
    Merci! Vous me conseillez mysqli ou pdo?


    Citation Envoyé par mathieu Voir le message
    en ce qui concerne votre question initiale je ne suis pas sur d'avoir bien compris.
    vous voulez économiser le temps de calcul de la requête en stockant le résultat dans un genre de fichier de cache ?
    Je récupère 3 millions de points dans une table SQL, je les stockent dans un fichier, et je les donnent au logiciel gnuplot qui en fait un graph pour mon interface html.
    En gros j'ai fait une page web qui permet de rejouer les telemetries de satellites. Mon besoin initial etait definit ici: https://www.developpez.net/forums/d1...s-issus-mysql/

  7. #7
    Modératrice
    Avatar de Celira
    Femme Profil pro
    Développeuse PHP/Java
    Inscrit en
    Avril 2007
    Messages
    8 633
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeuse PHP/Java
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2007
    Messages : 8 633
    Par défaut
    Personnellement, je préfère PDO, de loin. ça donnerait quelque chose comme ça (en utilisant le script de connexion de PDO une soupe et au lit !)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $db = include 'db_mysql.php';
     
    $sql = "SELECT UNIX_TIMESTAMP(`TIME2`) AS the_time2, `speed` AS speed, `friction` AS friction FROM `$theMnemo` WHERE `time` >= :start AND `time` <= :stop AND NOT `speed` = 0 AND NOT `friction` = 0";
     
    $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false); // unbuffered
     
    $stmt = $db->prepare($sql);
    $stmt->execute([':start' => $starts[$i], ':stop' => $stops[$i]]);
     
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    // ...
    Aucune idée de si ça a un impact sur les performances.
    Modératrice PHP
    Aucun navigateur ne propose d'extension boule-de-cristal : postez votre code et vos messages d'erreurs. (Rappel : "ça ne marche pas" n'est pas un message d'erreur)
    Cherchez un peu avant poser votre question : Cours et Tutoriels PHP - FAQ PHP - PDO une soupe et au lit !.

    Affichez votre code en couleurs : [CODE=php][/CODE] (bouton # de l'éditeur) et [C=php][/C]

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

Discussions similaires

  1. [AC-2007] Requête pour Changer les Résultats d'une autre requête
    Par Cloé_de_Bourg dans le forum Requêtes et SQL.
    Réponses: 2
    Dernier message: 05/11/2009, 13h33
  2. Sauvegarde de résultats dans une boucle FOR-END
    Par laroche1 dans le forum MATLAB
    Réponses: 4
    Dernier message: 19/12/2007, 16h51
  3. Problème pour récupérer le résultat d'une requête
    Par emeraudes dans le forum Hibernate
    Réponses: 1
    Dernier message: 27/07/2007, 10h01
  4. Réponses: 2
    Dernier message: 04/04/2007, 15h51
  5. Affiche d'un message pour afficher le résultat d'une commande
    Par celcy dans le forum VB 6 et antérieur
    Réponses: 1
    Dernier message: 26/01/2007, 19h59

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