Bonjour à tous,
Comme un peu toute la communauté des développeurs PHP, je me suis laissé convaincre d'utiliser la classe PDO pour accéder à mes BDD. On connait tous les arguments habituellement avancés:
- Pseudo-couche d'abstraction des BDD
- Possibilité de personnalisation de la classe par extension
- gestion des exceptions
- Possibilité d'utiliser des "Prepared Statements"
- Meilleure sécurité contre les injections SQL
- Amélioration des performances
- sur le parse des query répétitives
- sur le protocole binaire client-serveur (au lieu de chaine de caractères).
- Ça en jette un max et ça fait "übergeek"
Pour ma part, je suis d'accord sur les points 1 à 3 mais suis plus circonspect au sujet des avantages annoncés des
prepared statments. On lit (presque) partout que leur utilisation conduit à une amélioration sensible des perf pour des query répétitives comme des SELECT consécutifs dont seuls les paramètres changent. Ou des INSERT en série. J'ai donc testé mais ne suis pas arrivé à dégager d'amélioration sensible par rapport aux extensions mysql et mysqli de PHP. J'ai un peu gratté et il se fait que, par défaut, les Prepared Statement de PDO se font en mode client-side (PDO::ATTR_EMULATE_PREPARES=> true) une émulation de ce que fait le serveur MySQL en quelque sorte. De ce fait, on se retrouve avec quelques limitations:
- PDO met des quote autour des INT dans les requêtes envoyées au serveur MySQL.
SELECT * FROM matable WHERE id > 3 devient SELECT * FROM matable WHERE id > '3' dans les log de MySQL sauf si on utilise PDOStatement::bindValue en utilisant son paramètre optionnel data_type. Imaginez de faire un prepare sur SELECT * FROM matable LIMIT ? qui devient SELECT * FROM matable LIMIT '1' une fois arrivé sur le serveur MySQL. Va pas être content le serveur.
- Contrairement à ce la doc PHP prétend, il n'y a pas de validation de la requête sur le serveur MySQL avant de la lui envoyer pour exécution. En mode émulation (client-side prepare), une requête comme SELECT ice FROM artica AND antarctica n'est pas une requête SQL valide mais ne donnera pas d'erreur dans la phase prepare.
http://bugs.php.net/bug.php?id=44169
Pour pallier ces - disons - "bugs by design" on peut basculer en mode prepare natif (MySQL server-side) avec PDO::ATTR_EMULATE_PREPARES à false. On supprime les bugs du PDO en mode émulation et on peut arriver à un légère amélioration des performances sur des INSERT successifs (de l'ordre de 10% dans mes tests) MAIS:
Les requêtes preparées (server-side) ne sont pas cachées par MySQL! Du moins dans la version la plus courante (< 5.1.17). Et la pénalité de travailler hors cache est infiniment plus élevée que le malheureux gain de 10% puisque l'utilisation du cache de MySQL peut déboucher sur des gains de plusieurs centaines de pourcents.
Pour vous en convaincre, faites le test chez vous:
mysql> SHOW STATUS LIKE 'Qcache_queries_in_cache';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| Qcache_queries_in_cache | 0 |
+-------------------------+-------+
1 row in set (0.00 sec)
mysql> SELECT * FROM maTable WHERE code = 1234567;
Empty set (0.05 sec)
mysql> SHOW STATUS LIKE 'Qcache_queries_in_cache';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| Qcache_queries_in_cache | 1 |
+-------------------------+-------+
1 row in set (0.00 sec)
mysql> PREPARE myStmt FROM "SELECT * FROM maTable WHERE code = ?"; SET @code = 1234567; EXECUTE myStmt USING @code;
Query OK, 0 rows affected (0.00 sec)
Statement prepared
Query OK, 0 rows affected (0.00 sec)
Empty set (0.04 sec)
mysql> SHOW STATUS LIKE 'Qcache_queries_in_cache';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| Qcache_queries_in_cache | 1 |
+-------------------------+-------+
1 row in set (0.00 sec)
Vous verrez bien que le compteur de queries cachées n'augmentera pas avec les
prepared statements.
Alors pourquoi est-ce que je continue malgré tout à utiliser PDO? Et bien, d'une part parce que les autres avantages cités restent réels, aussi parce que je n'ai pas envie de revenir en arrière et de changer tout mon code et enfin parce que la communauté PHP mais aussi MySQL prepare de nouvelles versions pour mieux supporter les Prepare Statements: à partir de MySQL server > 5.1.17 les PS
seront cachées. Et, du côté de PHP, ça bouge aussi: le pilote PHP
MySQL Client Library devrait être remplacé par le nouveau
PHP PDO Native Driver qui devrait être livré avec PHP 5.3 ou PHP 6.
__________________________________
Références:
http://blog.ulf-wendel.de/?p=187#pdo
http://dev.mysql.com/tech-resources/art ... ments.html