Page 1 sur 1

PDO et mémoire

Posté : 23 août 2011, 03:13
par devlop78
Bonjour à tous,

Encore un problème que je n'ai pas réussi à résoudre. En lisant les détails des fonctions de l'API C de MySQL, l'extension mysql de PHP et PDO, je trouve des détails qui ne me semblent pas cohérents.

-> l'API de MySQL indique deux modes de récupération des données : l'une qui récupère ligne après ligne, et l'autre tout d'un coup. Il est aussi indiqué que dans le cas de ligne après ligne, il est obligatoire de terminer l'opération de récupération pour fermer la requête (je n'ai pas la doc sous les yeux, mais en gros c'est ça). Il est aussi indiqué qu'il n'est pas possible de connaître le nombre de résultats d'un SELECT pour la récupération ligne après ligne.

-> PDO indique que closeCursor() permet justement de fermer cette requête, soit avec (d'après ce que j'ai compris) une méthode adaptée au driver, soit, et c'est montré en exemple, en récupérant les lignes jusqu'à la dernière (sauf quelque driver qui ne le permettrait pas). Toutefois, il parait tout à fait capable de retourner le nombre de résultats d'un SELECT, et ne précise pas sa propre méthode de récupération.

-> Mysql permet de récupérer le nombre de résultats (c'est clairement dit que c'est possible pour un SELECT), et il existe mysql_unbuffered_query qui semble se comporter en lecture ligne après ligne, je cite "envoie la requête SQL query à MySQL sans automatiquement récupérer et mettre en mémoire les lignes du résultat, comme pourrait le faire la fonction mysql_query()."

Alors, si l'extension récupère l'ensemble des lignes du résultat, en quoi fetchAll() est-il mauvais pour la mémoire, puisque les résultats sont déjà dans l'extension ? Est-ce que la mémoire occupée par l'extension n'est pas prise en compte par la mémoire maximale d'un script php et donc c'est par rapport à cela ? Car d'après pas mal de tuto, ils ne le précisent pas et l'on peut penser que c'est de façon générale, sur le serveur client mysql (le même où tourne php) que cela peut poser un problème, et non pour la mémoire max d'un script. Exemple de la doc PHP sur PDO : "L'utilisation de cette méthode pour récupérer de gros jeux de résultats peut augmenter les ressources du système, mais également ces ressources". Ressources système c'est pas script php pour moi ...


Quelque chose m'échappe, peut-être ?

Pas mal de choses qui sont liées ne sont pas claires, pour le moment je commence avec celle-là. En gros, ça serait bien de savoir quand et où sont stockées les résultats, en fonction de ce que l'on fait ...

PS : Comme d'habitude avec moi, tout article externe est la bienvenue.

Re: PDO et mémoire

Posté : 23 août 2011, 11:40
par xTG
PDO permet la récupération ligne après ligne sans mise en mémoire.
Mais lors d'un comptage des lignes il ouvre un second curseur et parcours tout les n-uplets.
J'avais lu ça dans un article, si je te le retrouve je posterai le lien. ;)

Re: PDO et mémoire

Posté : 23 août 2011, 20:38
par devlop78
Ca serait nickel ! ;)

Re: PDO et mémoire

Posté : 23 août 2011, 20:43
par devlop78
Ce que je trouve quand même étonnant c'est que mysql ne sache pas lui-même combien il a de lignes ^^
Un avantage de mysql_store_result() est que puisque toutes les lignes ont été récupérées dans le client, vous ne pouvez pas que accéder aux lignes séquentiellement, vous pouvez revenir en arrière ou avancer dans le jeu de résultats en utilisant mysql_data_seek() ou mysql_row_seek() pour changer la position de la ligne courante dans le jeu de résultats
Ce qui est drôle là, c'est que, si le client mysql a bien toutes les lignes chez lui, pourquoi utiliserait-il mysql_data_seek pour se trimbaler dedans ???
Un avantage de mysql_use_result() est que le client a besoin de moins de mémoire pour le jeu de résultats car il utilise une ligne à la fois (et puisque il y a moins de pertes de mémoire, mysql_use_result() peut être plus rapide). Les inconvénients sont que vous devez récupérer chaque ligne rapidement pour éviter de bloquer le serveur, vous n'avez pas d'accès aléatoires aux lignes dans le jeu de résultats (vous ne pouvez accéder aux lignes que séquentiellement), et vous ne savez pas combien de lignes comporte le jeu de résultats tant que vous ne les avez pas toutes récupérées

Re: PDO et mémoire

Posté : 23 août 2011, 20:57
par devlop78
Par contre un document dit que mysql_use_result ne permet pas l'execution d'une autre requête tant que toutes les lignes de celle-ci n'ont pas été récupérées. Combien de fois j'ai vu des while($machin = mysql_fetch...) { mysql_query(...); } Et pourtant ça marche !

Re: PDO et mémoire

Posté : 24 août 2011, 02:04
par devlop78
memory_get_usage() donne un résultat différent entre avant et après un query(), mais aucun changement, en appelant successivement rowCount(), fetch() et fetchAll(). Pour PDO.

Remarque intéressante :
Cela lit le résultat directement à partir du serveur sans l'enregistrer dans une table temporaire ou un tampon local, ce qui est plus rapide et utilise moins de mémoire que mysql_store_result()
Ici, documentation sur la fonction mysql_use_result, ils parlent de table temporaire. C'est donc à croire que quelque soit la méthode utilisée, les données restent côté serveur mysql. D'un autre côté, mysql_store_result donne l'impression que le client mysql écrit en C alloue la mémoire dès le départ pour l'ensemble des résultats qui vont être rapatriés, ce qui pourrait expliquer aucune différence dans PDO avec les méthodes utilisées, et qui pourrait expliquer pourquoi il est en mesure de donner le nombre de lignes (mais pourtant dans certaines docs PDO::MYSQL_ATTR_USE_BUFFERED_QUERY semble être à false par défaut).

En gros, faites pas ça, mais sans aucune raison. fetchAll() serait donc uniquement problématique pour la taille des variables php ? En attendant, la mémoire est bien utilisée par PDO et potentiellement explosée par des requêtes avec de gros retours ... Suspens

Re: PDO et mémoire

Posté : 24 août 2011, 02:30
par devlop78
Aller ... Encore une avancée ;)

PDO::MYSQL_ATTR_USE_BUFFERED_QUERY à true (par défaut)

lorsque le query(à est effectué, la mémoire explose. rowCount() donne une bonne valeur. Une requête est aussi possible juste après, alors qu'aucune fermeture ou récupération de donnée n'a été effectuée.

Passée à false, la mémoire augmente mais assez peu. rowCount() donne 0.

Donc par défaut je peux en déduire que PDO utilise mysql_store_result, et donc ce n'est que par rapport au stockage du résultat de fetchAll() dans un tableau que cela pose problème, et non pour des raisons de ressources systèmes et tout le tralala. Une requête lancée après ça lance une exception, sauf si closeCursor() ou fetchAll() a été fait (ce dernier est d'ailleurs suggéré par PDO lui-même)