Mysql va arriver en version 5.6

Dans un précédent article, j’annonçais que PHP dépréciait l’API mysql_ de manière officielle pour ne laisser que PDO et Mysqli. Une des forces de ces deux API, c’est que contrairement à leur ancêtre, elles prennent en compte les nouveautés apparues dans mysql 5.1+. Il y a une deux semaines, Oracle -qui possède désormais Mysql- a annoncé la version 5.6, et vue les nouvelles fonctionnalités, ça serait vraiment dommage de se passer de tout ça non?

Des optimisations à gogo

Oracle aime bien faire évoluer très rapidement les technos qu’il rachète. Ainsi en plus de casser Java ils ont décidé d’améliorer grandement MySQL, n’en déplaise à son créateur qui a forké le tout pour créer MariaDB. Et pour le coup ce sont des optimisations qui sont à l’oeuvre principalement.

On le sait, Mysql a un certain retard sur PgSQL en matière de rapidité, et ce ne sont pas les moteurs alternatifs à InnoDB comme MyISAM qui vont mettre en péril la domination de ce SGBDR là. Pourtant Oracle, petit à petit travaille sur les caches SQL -notamment pour les requêtes préparées du côté du serveur Mysql-, l’optimisation des index etc.

En effet dans les premières versions de Mysql 5, qui ont permis à PDO et mysqli de s’envoler, Oracle comme PHP était obligés de déconseiller l’utilisation de requêtes préparées natives car Mysql ne les mettait pas en cache.
Cela signifiait que nous devions nécessairement passer par de l’émulation de la préparation par PDO/mysqli. La doc de PHP nous déconseillant d’écrire [icc lang=”php”]$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARE,false);[/icc].

Dans cette nouvelle mouture, l’optimisateur de requête est amélioré et reçoit notamment l’option « Index condition pushdown » pour les requêtes avec une clause WHERE sur des champs Index.

L’optimisation marche de cette manière :

  • Sans le Index condition pushdown :
    1. Va chercher la ligne suivante puis en utilisant les index il va localiser et lire la ligne entière
    2. Applique la clause WHERE qui correspond à la table et filtre la ligne en fonction du résultat.
  • Avec le Index condition pushdown :
    1. Va chercher le tuple d’index de la ligne suivante
    2. Regarde les conditions qui sont liées à l’index. Si le filtrage exclus la ligne, on passe à la suivante à partir de l’étape 1.
    3. Si le filtrage a accepté les index, la ligne entière est localisée et lue
    4. Enfin le reste de la clause WHERE (sans les index donc) est exécutée

     

Profilage facilité : nouvelle mise en forme pour la sortie EXPLAIN

La sorite EXPLAIN est utile lorsqu’on désire optimiser les requêtes les plus lourdes. Elle nous permet de mieux dimensionner nos colonnes (les VARCHAR entre autre), et surtout de mieux choisir nos index (unique, texte…).

Cette sortie est souvent utilisée en console lors du développement, mais avec la quantité de profiler intégrés aux IDE ou aux barre d’outil des versions de développement des applications (comme sur Symfony), opter pour un format léger, reconnu de tous, dans tous les langages et facile à parser est important. La montée en puissance de JavaSript et de Node.js aura sûrement été un argument supplémentaire lorsqu’Oracle a choisi d’utiliser JSON pour faire ça.

Un peu de NoSQL dans MySQL :

Une API expérimentale fait son apparition dans MySQL qui a pour but d’être utilisée avec Memcached afin d’accélérer les recherches en base de données.  Une piste d’amélioration sûrement conséquente non?

Gestion de la mémoire avec PHP

Aujourd’hui, Frédéric Hardy aka mageekguy a posté un article en ce qui concerne la gestion de la mémoire en php. Cet article se veut une réaction à celui-ci qui explique en regardant au sein du code source de php comment le langage gère la mémoire.

Si je reviens sur ces deux articles c’est que l’article original m’a un peu laissé sur ma faim et que le second m’a quand même choqué. Je n’ai peut être pas l’expertise ni l’aura de Frédéric Hardy, mais je n’arrive pas à me retrouver dans sa sentence : “idiot”.

Je ne reviendrais pas sur les arguments de ceux qui sont pour ou qui sont contre cet assassinat éditorial, mais je me concentrerai un peu sur la technique.Ou du moins ce que j’en connais et ce que ces articles m’ont appris.

Frédéric Hardy a le mérite, malgré ses propos agressifs de donner des exemples techniques et des conseils de bonnes pratique. Pour tous ceux qu’il cite, je les connaissais mais je croyais que c’était plus de la bidouille très geek de la part de quelqu’un qui est passionné par php que des pratiques très professionnelles.

En gros il y a deux grands points de “bonne pratique” qui doivent être respectée. La première concerne le code en lui même : utiliser, quand c’est souhaitable la fonction unset, comme par exemple, à la fin d’un foreach, ou bien pour libérer un tableau dont on n’a plus besoin (les tableaux php sont particulièrement lourds !).

D’ailleurs, c’est bien ça qui me fait dire que l’avis de Frédéric Hardy est trop totalitaire.
Comment savoir que l’usage de unset est souhaitable si on se fie simplement à l’instinct? On pourrait se dire que c’est clair qu’un tableau c’est plus lourd qu’un simple entier et donc que c’est là que ça devient utile. Oui mais non. En C une chaîne de caractères, c’est un tableau de caractères. Imaginons qu’on utilise une norme particulièrement gourmande en taille telle que UTF-32 pour représenter un caractère. Une chaîne UTF-32 prend donc autant de place qu’un tableau de int.
A l’opposé, en php faire un tableau de caractère ou une chaîne de caractère ce n’est pas pareil, même si l’opérateur crochet a été surchargé pour les strings. Ainsi même un simple array(‘a’); prendra plus de place que la chaîne de caractère “francoisdambrine.olympe.in”.

Autre exemple de code : les requêtes non bufferisées.
J’avais plus ou moins conscience de ce que c’était, mais je continuais quand même d’utiliser à tout va des fetchAll par pure facilité en m’assurant juste que ma requête ne prenait pas trop de résultat. En fait il semblerait que cette pratique sans être particulièrement mauvaise devrait être bien moins systématique.

Ensuite, le conseil de mageekguy : laisser aller ou bien utilisez un autre langage.

Par contre, des optimisations peuvent être amenées via l’environnement. Et là les deux le disent, c’est juste la forme qui change. C’est pourquoi je ne comprends pas que mageekguy soit si agressif : cache d’opcode, utilisation de la dernière version de php, tous les deux le disent.
Petite astuce apparemment utilisée en milieu professionnel et aussi par le geek que je suis : compilez vous même les versions de php. Cela permet de réduire grandement l’usage de mémoire.

Et en ce qui concerne l’Opcode, une bonne nouvelle a été annoncée sur la liste de diffusion de php il y a peu : ZendOptimiser+ va passer open source et est candidat pour être le moteur de cache par défaut de php. Si un tel moteur manque dans le coeur de php de manière évidente, ZO+ a l’avantage d’optimiser la compilation en opcode améliorant ainsi les dernières avancées de php 5.4 et 5.5.

 

PHP 5.5 déprécie Mysql

Ca y est ! la version 5.5 de PHP qui est actuellement en version alpha jusque jeudi a marqué l’API Mysql qui commençait à dater comme dépréciée.

Cela signifie que désormais, à chaque appel de mysql_connect (ou de son équivalent pour les connexions persistantes) un WARNING vous sera envoyé vous conseillant de passer à Mysqli ou PDO. Si vous ne l’avez pas déjà fait, il n’est pas trop tard, et je vais vous rappeler (ou du moins vous présenter) quelques bonnes raisons de ce passage :

La sécurité

On ne vous le dira jamais assez, mysqli et PDO sont plus sécurisés. Pas simplement parce qu’ils proposent les requêtes préparées, qui sont naturellement “sécurisées” (à condition qu’on sache s’en servir) mais aussi parce que l’un comme l’autre corrigent les failles de mysql_ en ce qui concernent l’encodage, les connexions persistantes etc. Cela impliques quelques règles à respecter :

  • Il est obligatoire de donner la ressource de connexion à chaque fonction qu’on appelle. La POO simplifie cela puisque la méthode est liée au $this. Par contre le style procédural permis par mysqli_ vous oblige à écrire par exemple :[cc lang=”php”]$query = mysqli_query($connexion,’SELECT * FROM yourtable’);
    $result = mysqli_fetch_all($query);[/cc]
  • Sauf pour les requêtes dont vous savez qu’elles n’utilisent pas de paramètres, utilisez la fonction prepare. Attention néanmoins mysqli_ et PDO n’utilisent pas cette fonction de la même manière. PDO a deux grands avantages sur MySQLi en ce qui concerne les requêtes préparées : il permet des paramètres nommés et il permet de lier une valeur plutôt qu’une variable. Enfin pour PDO aller chercher le résultat d’une requête “normale” ou d’une requête préparée c’est la même chose donc les méthodes fetchAll et fetch existeront. Pour mysqli seul fetch existera et encore, il fonctionnera d’une autre manière que le fetch d’une requête normale.
    • Exemple de requête préparée avec PDO : [cc lang=”php”]$pdo = new PDO(‘yourDSN’,’user’,’pw’);
      $prep = $pdo->prepare(‘SELECT * FROM yourtable WHERE yourcol=:yourcol’);
      $prep->bindValue(‘yourcol’,"une chaîne avec des c’haractères embêt@nts’");
      $prep->execute();
      $result= $prep->fetchAll(PDO::FETCH_ASSOC);[/cc]
    • Exemple de requête préparée avec MySQLi :[cc lang=”php”]$mysqli = new mysqli(‘yourhost’,’user’,’pw’,’db’);
      $prep = $mysqli->prepare(‘SELECT * FROM yourtable WHERE yourcol=?’);
      $var = "une chaîne avec des c’haractères embêt@nts’",
      $prep->bindParam(‘s’,$var);
      $prep->bindResult($col1,$col2,$col3);//les résultats de chaque colonnes seront mis dans les variables associés
      $prep->execute();
      while($prep->fetch()){
      $result[] = array($col1,$col2,$col3);
      }[/cc]

     

Les fonctionnalités

L’ancienne API est ancienne et n’a pas été mise à jour avec Mysql 5 donc contrairement à PDO et mysqli elle ne pourra pas tout faire.
Au programme : requêtes multiples, support amélioré des transaction, support amélioré des conexions persistantes…

Migrer? mais comment?

En utilisant l’outil développé par Oracle.
En allant chercher quelques infos sur stackoverflow.