Erreur sur une requête

Avec de vrais morceaux de "Allowed memory size exhausted" dedans

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour,

Avant toute chose, je dois vous avertir que le projet sur lequel je travaille concerne des informations commercialement sensibles pour la société chez laquelle je réalise mon stage, raison pour laquelle certaines parties de mon code seront passées sous silence. Je vais cependant essayer d'être suffisamment clair pour que vous puissiez m'aider à résoudre mon problème.

En gros, on m'a demandé de faire évoluer un Pokémon un petit site en PHP qui récupère des données dans une base de données Oracle afin de l'exporter dans un fichier au format CSV, selon une requête SQL de type SELECT écrite à l'avance par les administrateurs et stockée dans une base MySQL. Précédemment, cette requête SQL était écrite "en dur" dans le code du site.

Mon problème, c'est qu'une requête, bien qu'elle n'ait pas changée entre la version précédente et celle que je développe, ne fonctionne plus correctement : désormais, PHP me lâche l'erreur suivante :

Fatal error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 83 bytes) in /chemin/vers/le/modele.php on line 199

La requête en question retourne en général entre 2000 et 3000 lignes.

EDIT : petite chose cocasse, une autre requête utilisant cette même fonction ne pose strictement aucun problème alors qu'elle retourne quasiment 6000 lignes…

Voici la fonction que j'appelle lorsque j'exécute ma requête :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?php
    public function exec_requete_oracle($query)
    {
        $result = array();

        $data = $this->db_ora->query($query);
        $data = $data->fetchAll(PDO::FETCH_ASSOC);

        // On ajoute au début du tableau les noms des champs sélectionnés,
        // afin qu'ils apparaissent dans le CSV
        $columns_name =  array_keys($data[0]);
        array_unshift($data, $columns_name);

        return $data;
    }

Notons que je suis certain de mon paramètre $query, ayant effectué plusieurs fois des vérifications, notamment des recherches de différences entre la requête précédant mon évolution (qui fonctionnait, je le répète), sans succès…

L'erreur se déclenche sur le fetchAll()… Sachant que je dois obligatoirement obtenir un tableau contenant l'intégralité des données, celles-ci étant ensuite envoyées à une fonction créant le CSV, comment puis-je résoudre ce problème ? :-/

Merci d'avance

Édité par Jérôme Deuchnord

A graphical interface is like a joke: if you have to explain it, that's shit. | Les logiciels Deuchnord

+0 -0
Auteur du sujet

Est-ce que l'autre fonciton qui utilise cette requête fait aussi un fetchAll ?

En fait, l'autre fonction fait exactement la même chose. La seule différence entre les deux est que dans l'ancienne, la requête à exécuter se trouvait dans une variable directement dans la fonction, et non donnée en paramètre.

Perso je ferais un fetch simple et une boucle.

J'y ai pensé, mais comme au final je dois donner les données sous la forme d'un tableau pour qu'il soit transformé en CSV… :-°

A graphical interface is like a joke: if you have to explain it, that's shit. | Les logiciels Deuchnord

+0 -0
Staff

Cette réponse a aidé l'auteur du sujet

Perso je ferais un fetch simple et une boucle.

J'y ai pensé, mais comme au final je dois donner les données sous la forme d'un tableau pour qu'il soit transformé en CSV… :-°

Moui. Je ferais pas ça perso, parce que niveau conso mémoire ça va manger. Je ferais du fputcsv ligne par ligne.

Je parle de JavaScript et d'autres trucs sur mon blog : https://draft.li/blog

+1 -0
Auteur du sujet

Bonjour,

Merci pour ta réponse, on avance, je n'ai plus le problème de l'épuisement de mémoire :)

Cependant, j'ai un autre problème : j'ai un soucis de performances débouchant sur une erreur Maximum execution time of 300 seconds exceeded

Voici en effet mon code (la ligne surlignée est celle sur laquelle le script plante) :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php
// Plus haut, on a ouvert un fichier pour y mettre le contenu du CSV
        $firstLine = true;
        while($line = $data->fetch(PDO::FETCH_ASSOC))
        {
            if($firstLine)
            {
                $heading = array_keys($line);
                fputcsv($fp, $this->array_utf8_decode($heading), ';', chr(0)) or die('Erreur lors de la lecture des données');
                $firstLine = false;
            }

            fputcsv($fp, $this->array_utf8_decode($line), ';', chr(0)) or die('Erreur lors de l\'écriture des données');
        }

As-tu une idée pour optimiser l'exécution de mon code ? Sachant que array_utf8_decode() applique la fonction utf8_decode() sur chaque élément de l'array passé en paramètre. Elle s'exécute donc à l'aide d'un foreach().

Je me demande si fputcsv() ne provoque pas un appel système (ce qui est lourd) au moment d'écrire dans le fichier ? Dans ce cas, existe-t-il un moyen d'optimiser cet appel système ?

Merci à toi :)

A graphical interface is like a joke: if you have to explain it, that's shit. | Les logiciels Deuchnord

+0 -0
Auteur du sujet

J'ai finalement réussi à résoudre mon problème !

Le problème ne venait en fait pas de la boucle de mon message précédent mais de la requête SQL qui n'était pas correctement lue à cause de problèmes d'encodage. Il y avait en effet une ligne commentée au beau milieu de la requête. Or, les retours à la ligne sont mal digérés par Oracle en raison de l'encodage différent, ce qui fait qu'une partie de la se retrouvait commentée par erreur.

Résultat : beaucoup plus de résultats que prévus, résultant un plantage pour cause script PHP trop long.

Merci en tout cas pour ton aide, Victor, PDOStatement::fetchAll() ne m'aurait de toute façon pas aidé sur ce coup-là :)

Édité par Jérôme Deuchnord

A graphical interface is like a joke: if you have to explain it, that's shit. | Les logiciels Deuchnord

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte