PDO - Différence entre Prepare et query ?

Eléphant du PHP | 168 Messages

08 mai 2009, 11:28

Salut à tous !

Alors je suis entrain de me mettre à jour étant donné que dans PHP6, seul PDO sera disponible.

J'ai encore quelques doutes sur l'utilisation de l'un ou de l'autre.. (prepare ou query)

L'avantage de prepare, c'est qu'il compile la requete et permet de s'en reservir plus rapidement sans refaire l'arbre je ne suis plus comment :)
M'enfin ma question n'est pas là !

Ma question est sur le point qui dit "utiliser prepare si vous vous resservai de la meme requete avec des parametres différents".
Par cette phrase, ca veut dire dans la "meme" page ? ou sur le site ?

Car admettons que j'affiche l'id 2 de mon article, si on va voir une autre page avec l'id 3, c'est compris comme la meme requete mais avec des parametres diff ?

Dans ce cas là, a quoi sert query, ou plutot dans quel cas faut il l'utiliser ?

Derniere question, il dise que apres "chaque" reqs, la fermer avec CloseCursor, et fermer egalement la connexion avec $connexion = null;

Si je fais ça, ca annule pas la possibilité de se resservir de la meme requete ? puisque la connexion est refermée ?

Et par rapport au nombre de connexion a la base en simultané, si elle est admettons de 3, et que j'ai 3 reqs, sur ma page, si a chaque req, je co, et deco, multiplié par le nbre de personnes sur la page, je fais vite atteindre la limite non ?
Ne faut il pas mieux lancer la connexion en haut et laisser php la fermer a la fin de la page ?

Merci d'avance

ViPHP
ViPHP | 4674 Messages

09 mai 2009, 00:37

Hey :),

Il faut considérer le problème d'une façon plus générale. Tout d'abord, sache que les serveurs de bases de données ont des systèmes de cache qui leurs sont propres, c'est à dire que le rôle de PHP est de mettre en cache les résultats d'une requête, mais c'est au serveur de bases de données de gérer les caches des requêtes et des possibles résultats.

Pour forcer cette utilisation du cache, on utilise les requêtes préparées. Trivialement, on utilise une requête préparée lorsqu'on souhaite utiliser plusieurs fois la même requête mais avec un minimum de paramètres (condition par exemple, à l'aide de la clause WHERE) qui sont susceptibles de différer. Typiquement :

Code : Tout sélectionner

SELECT id, label FROM table WHERE id = ?
L'identifiant peut changer régulièrement. On va préparer cette requête, binder les variables et exécuter la requête.

En fait, pour ne pas réécrire 25 fois la même chose, je te conseille de lire le manuel du paquetage Hoa_Database_Dal, section Manipuler les requêtes. Le système est calqué sur PDO, tu y trouveras exactement les mêmes notions. Ne t'occupes pas des objets utilisés, mais seulement des définitions.

Pour répondre à tes questions maintenant : une requête préparée l'est pour plusieurs instances de ton application. Une page ne signifie rien. On parle de connexion au serveur de base de données.

La réponse à query se trouve dans le manuel de Hoa_Database_Dal. Pareil pour closeCursor.

Enfin, le mieux est d'ouvrir une connexion n'importe où dans le programme (si nécessaire donc) et de la fermer à la fin du programme. Si jamais une nouvelle brique de ton programme a besoin de la connexion, il pourra l'utiliser sans se soucier de quoi que ce soit.

Il faut bien comprendre que PHP est très rapide, mais aussi que les RDBMS le sont tout autant. En revanche, ce qui est lent, ce sont les échanges entre PHP et les RDBMS, qu'il faut éviter au maximum. Donc écrire des grosses requêtes est plus rapide que d'en écrire plusieurs petites. Pareil pour les connexions : elles sont longues et lentes, mais maintenir (temporiser, mémoriser) une connexion ouverture est très peu coûteux.
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

Eléphant du PHP | 168 Messages

09 mai 2009, 10:01

Super explication, mieux que la doc officielle :lol:

Quelques petites dernières questions :
Si on ne traite pas toutes les données du jeu retourné par query, on doit libérer les ressources et la connexion au serveur pour pouvoir ré-exécuter la méthode query. Pour ça, on utilise la méthode closeCursor sur notre résultat, donc sur la classe Hoa_Database_Dal_DalStatement. Par défaut, query traite toutes les données, donc on n'a théoriquement pas besoin d'utiliser closeCursor sauf si une erreur se produit
Tous les resultats retourné par query veut dit quoi ?
As tu un exemple et contre exemple, pour comprendre la nuance.
Car je pense pas qu'elle soit au niveau de fetch (1 resultat ) ou fetchAll (tous )

Sinon pour le reste, si j'ai bien compris, une req sans parametre doit être réalisé avec Query, même dans le cas où elle est lourde en "jointure" ?

Des que nous avons des parametres, pour une question de performance de cache, et de securité, c'est plus prudent d'utiliser prepare, meme si ya du ORDER BY, du WHERE et du LIMIT ? car je sais pas si la BDD fait la même req et l'ordonne ensuite ou si ca represente une toute autre requete.

Last question : J'ai vu des personnes utilisés prepare pour faire de l'INSERTION, UPDATE, DELETE, à la place de exec, d'un premier abord j'en vois pas la logique, puisque chaque opération est unique, mais sait on jamais ya peut etre une subtilité quelque part.

En tout cas, tu m'as déjà bien éclairé ;)

Merci

ViPHP
ViPHP | 4674 Messages

10 mai 2009, 00:07

Hmm, bon, je ne suis pas certain à 200% que mon explication est correcte mais elle a au moins l'avantage de vulgariser l'idée.

query va exécuter la requête et retourner les résultats. Résultats que l'on peut obtenir via un fetch. Qu'est-ce qu'il se passe derrière ? Il y a plusieurs solutions mais je pense que la seule viable est la suivante. La requête s'exécute et le résultat est temporisé dans une nouvelle table (ce qui serait logique, car c'est le fonctionnement des jointures par exemple). Ensuite, fetch va avancer le pointeur de cette table et lire la ligne, jusqu'à arriver à la fin de la table. C'est le même fonctionnement qu'un itérateur en fait (si tu connais). On peut parler de pointeur ou (suspense) de curseur. À mon avis, si on parle de fermer le curseur, ça signifie libérer la mémoire de cette ressource, soit supprimer la table. Je pense que cette opération se fait naturellement lorsque fetch arrive en bout de table (i.e. au dernier enregistrement). Donc si fetch n'y arrive pas, on peut théoriquement le forcer.
Mais (et c'est là que ça devient intéressant), on peut créer des tables intermédiaires pour nos requêtes. Par exemple, une jointure, comme dit précédement, crée des tables temporaires sur lesquelles on effectue de nouvelles comparaisons pour obtenir encore une nouvelle table etc. Pareil pour des sous-requêtes. Après, chaque RDBMS a sa façon de faire, mais si on s'en tient à la théorie des ensembles et la théorie relationnelle (très proches), ça devrait fonctionner comme ça. Donc donc donc : si des tables sont en cours de création mais qu'une erreur survient, on doit être capable (si le RDBMS ne le fait pas) de les vider puis de les supprimer, soit de clôturer le curseur.
Ce qui m'intrigue avec cette dernière notion, c'est que c'est théoriquement à l'RDBMS de gérer ce cas, pas à nous. Toutefois, en cas de crash ou ce genre de chose, on doit être capable de reprendre les traitements (ce qui est possible avec Oracle il me semble). Ainsi, ça aurait un sens.

Préparer ses requêtes est préférable dans tous les cas. Bien sûr, c'est à peine plus lent (plus on a de fonctionnalités et plus c'est lent, logique !), mais ça vaut le coup sur la durée je pense.
Pourquoi le faire systématiquement ? Le RDBMS (selon son niveau de gestion des requêtes préparées bien sûr) ne va pas que faire un cache partiel de la requête, il va aussi être capable de prévoir les résultats, et, ainsi, de calculer les résultats plus rapidement.
Je conseille donc de toujours l'utiliser. Et ce, même si on navigue avec plusieurs objets côté PHP (PDO et PDOStatement).

Enfin, faire une préparation de requête pour une insertion, ce n'est peut-être pas idiot, car tu peux tout autant avoir des paramètres variables dans de telles requêtes :-).
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

Eléphant du PHP | 168 Messages

10 mai 2009, 00:51

Ouah.. :shock:

Ca, c'est de l'explication.. on sent la maitrise et surtout la passion.

J'ai eu besoin de le relire à plusieurs fois pour bien imprégner le sens.

C'est dans ces moments là, que je réalise que je ne sais pas grand chose :lol: comparé à d'autres.
Tu as tellement expliqué dans les détails que j'en suis limite plus perdu qu'avant :roll:
Et vu le temps que tu passes à m'expliquer clairement, j'ai un peu honte :)


Moi qui passe de mes basiques mysql_query à PDO, ca m'a demandé une acclimatation, mais si on rajoute cette histoire de pointeur, je commence à me noyer :roll:

Alors sur le moment, je suis un peu coincé..
Essayer de tester ce que contient un fetch ou un fetchAll et jouer avec les autres méthodes pour essayer de comprendre à ma vitesse.
Ou abuser de ta bonté, et te demander de répondre à mes questions, sur lesquels mon esprit bute...

Bref bref.. voila.. je pensai pas que c'etait si obscur :?

ViPHP
ViPHP | 3300 Messages

10 mai 2009, 01:50

barf nico flatte pas l'égo d'hyWaN malheureux, il est doué certes mais moins on lui dit mieux c'est :)
Fait du php depuis que ca existe ou presque :)

ViPHP
ViPHP | 4674 Messages

10 mai 2009, 16:20

:-)

Désolé si je n'ai pas été assez clair. Le fait d'essayer de comprendre le fonctionnement de la clôture des curseurs me faisait penser que tu connaissais un peu le sujet. On va faire plus simple.

N'utilise pas la clôture de curseur, ça ne sert à rien pour 99,99% de tes cas. Ton RDBMS va le gérer à ta place. Si tu as des erreurs, ce sera en développement, et le GC (Garbage Collector) va faire le nettoyage à ta place.

Si tu souhaites seulement passer à PDO, tu n'as pas besoin de comprendre le fonctionnement des RDBMS de cette manière. Considère seulement que tu vas toujours préparer tes requêtes. Tu verras avec le temps et l'expérience que certaines peuvent être exécutées tout de suite, sans passer par un système de cache. Mais la réponse est étroitement liée à la relation entre ton pilote (driver) de base de données et ton RDBMS.

Est-ce que cette réponse te convient mieux :-) ?

Et ne pense pas que tu m'embêtes en reposant des questions. Tu es curieux, tu souhaites apprendre avec les bons outils, je ne peux que t'encourager. Et si je n'ai pas le temps pour répondre, je ne réponds pas (et ça reste à moi d'en juger ;-)). Donc pose tes questions !
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

Eléphant du PHP | 168 Messages

10 mai 2009, 19:26

Ouep, cette fois j'ai compris :)

Mille merci :wink:


Edit : Afin de continuer sur ma lancée, est t'il possible sans redefinir les methodes que si une erreur survient, d'appeler une autre methode qui par exemple envoie proprement un message en retour. ?

Et j'ai vu qu'il renvoie des "codes", j'arrive pas trouver tel code correspond a tel problème, afin de redefinir des messages en francais, et permettre par exemple, si trop de monde sont sur le site et sature Mysql, d'afficher un message expliquant de repasser dans quelques minutes.

Mammouth du PHP | 693 Messages

10 mai 2009, 20:40

Pour cela, il suffit de créer ta propre classe qui héritera de la classe PDO.

Tu peux ensuite surcharger chaque methode comme tu le souhaite. Un petit exemple :

class MyPDO extend PDO {

  function __construct($arg) {
    //appel du constructeur de PDO
    parent::__construct($arg);
  }

  function query($requet) {
    //appel de la fonction de PDO
    $result=parent::query($requet);
    /*
    traitement du résultat en cas d'erreur
    */
    return $result
  }
}

ViPHP
ViPHP | 4674 Messages

10 mai 2009, 23:05

C'est effectivement une façon de faire. C'est ce qu'on appelle un wrapper (ou emballeur en français :?).

Pour les codes d'erreur, aucun standard n'existe. Il faut gérer les documentations de chaque RDBMS.
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).