Oct/098
MySQL Query Cache
La query cache de MySQL joue un rôle important dans la performance de plusieurs sites Web. Elle a pour avantage d’être transparente, c’est-à-dire que la ou les applications qui s’en servent n’ont pas besoin d’être modifiées.
J’ai recu la semaine passée la question suivante (je résume):
Je souhaite utiliser une cache pour le menu de mon site afin de le rendre plus performant. Puisque le contenu du menu ne change pratiquement jamais, est-il plus avantageux d’utiliser APC Cache que la Query Cache de MySQL puisque la communication s’effectue selon un schéma comme:
php -> cache_apc (ram)
php -> mysql -> query_cache (ram)Je souhaite réduire au minimum les requêtes SQL exécutées.
Personnellement, j’utiliserais la cache de MySQL. Tout d’abord, il faut savoir qu’il y a une énorme différence entre les 2 caches.
MySQL Query Cache est centralisée sur le serveur MySQL, c’est-à-dire qu’elle utilise la RAM de la machine du serveur MySQL. Elle possède un mécanisme d’invalidation basique, mais efficace. L’invalidation se produit lorsque des valeurs d’une table sont en cache, et que ces valeurs sont mise à jour par une application ou manuellement par un utilisateur.
APC Cache est centralisée sur le serveur Web, c’est-à-dire qu’elle utilise la RAM disponible sur le serveur qui roule Apache et PHP (en supposant que vous utilisez Apache). Vous serez responsable d’invalider la cache lorsque nécessaire. Si quelqu’un modifie la valeur directement dans MySQL, la cache possèdera la vieille valeur jusqu’à ce qu’un processus l’invalide.
Puisque les données ne changent pratiquement jamais, je ne me casserais pas la tête à réinventer la roue. MySQL fait déjà pour vous ce que APC ferait, sans le moindre effort. De plus, il est plus ou moins vrai de dire que d’appeler la cache correspond à une requête. Oui, la string SQL est nécessairement envoyé à MySQL, mais lorsque celui-ci la reçoit et valide que cette requête est cachée, il retourne immédiatement le résultat sans rien “processer”. C’est comme ça que fonctionne APC aussi, il lui faut un identifiant unique pour associer le résultat, tout comme fait MySQL avec le HASH de la requête.
Les caches (peu importe laquelle) sont tout aussi efficaces avec une petite requête qui consomme peu de ressource qu’avec une grosse qui en demande beaucoup. Il est donc plus avantageux de cacher les processus lourds que les légers.
Ce qu’il faut surtout se soucier lorsqu’on utilise une cache, c’est comment et à quelle fréquence il faut l’invalider. Lorsque la Query Cache de MySQL est activée, le processus de cacher les résultats et de les invalider s’effectue tout seul de manière invisible. Ainsi, d’autres requêtes que vous ne soupçonnez même pas bénéficient de la cache. À l’inverse, il faut modifier le code pour chaque requête que vous souhaitez cacher avec APC.
Sep/092
Sondage: Storage engine non officiel
Depuis quelques années, beaucoup de storages engines ont vue le jour pour répondre à des besoins que les storages engines fournis avec MySQL ne font pas bien, voir pas du tout. Selon moi, la majorité d’entre eux sont des projets qui risquent mourir dans un proche avenir. Toujours selon moi, pour que les projets gratuits et opensource demeurent longtemps, il faut qu’ils jouissent d’une certaine popularité, ce que la majorité des storages engines ne possèdent pas. De plus, ils doivent être en mesure de prouver qu’ils sont sans faille; on ne peut se permettre de perdre des données à cause d’un engine immature.

Malgré tout, je crois en un storage engine non officiel: Percona-XtraDB. Il est basé sur le populaire engine InnoDB, mais offre de meilleures performances tout en demeurant 100% compatible à ce que InnoDB peut accomplir. On peut donc remplacer aveuglement InnoDB par XtraDB sans craindre quoi que ce soit! On pourrait ainsi dire qu’il s’agit d’un nouveau InnoDB, plus rapide et plus robuste.
Comme son nom l’indique, il est principalement développé par Percona, une entreprise pour laquelle j’ai un très grand respect. Bien qu’il soit encore jeune, j’ai confiance qu’il atteigne une maturité très rapidement. Je suis de très près son évolution et j’ai déjà élaboré quelques tests avec.
J’aimerais connaitre vos opinions sur les storages engines non officiels.
Sep/090
MySQL comme référence
Comme plusieurs savent déjà, je suis régulièrement sur IRC (sur Freenode) sur des canaux reliés à l’informatique. Je traîne notamment sur #MySQL et #MySQL-fr. Depuis peu, je vais sur #PostgreSQL histoire de voir ce qui se fait ailleurs et quel genre de problèmes les utilisateurs de PostgreSQL ont. Après quelques jours, j’ai remarqué quelque chose qui m’a fait sourire: les gens sur #postgresql comparent souvent Postgresql à MySQL.
Beaucoup d’entre eux tentent de migrer de MySQL vers PostgreSQL et sont heurtés à toutes sortes de petits problèmes. Ce que j’en retiens comme conclusion, c’est que MySQL est d’abord et avant tout le SGBD de premier choix. Davantage de gens connaissent et apprennent MySQL en premier, avant de potentiellement se tourner vers d’autres solutions. Il est souvent le point de référence pour savoir si un truc va mieux ou moins bien que les autres solutions comme PostgreSQL.
Aug/090
Importation d’un CSV
On m’a soumis un problème il y a quelques semaines (désolé du délai, c’est l’été pour tout le monde hein..
) à propos d’importation CSV qui était terriblement lente. J’ai reçu très peu d’information, donc voici des tests que j’ai effectués afin qu’il puissent être utilisés comme point de référence pour des comparaisons. Voici la problématique telle qu’on me l’a soumise
Pour un simple fichier CSV d’environ 1000 lignes (quelques Mo), j’ai largement le temps soit de manger, soit de faire une sieste, … pour une base de données MyISAM. Si j’utilise une base de données InnoDB, celle dont j’ai besoin, plus d’une journée. Je me base uniquement sur un seul utilisateur. A terme, j’aurai des To de données à gérer.
La Machine de tests:
Une VM avec 512 Mo de RAM avec un mauvais IO puisque d’autres VM roulent sur le même serveur. Voici un bout de la config que j’ai utilisé
key_buffer = 40M
max_allowed_packet = 16M
thread_stack = 256K
thread_cache_size = 8
thread_concurrency = 2
table_cache = 384
sort_buffer_size = 768K
read_buffer_size = 512K
read_rnd_buffer_size = 512K
La table de tests:
CREATE TABLE `csvimport` (
`a` int(11) NOT NULL,
`b` varchar(255) NOT NULL,
`c` varchar(255) NOT NULL,
`d` date NOT NULL
) ENGINE=CSV DEFAULT CHARSET=utf8
et un fichier CSV de 1114112 lignes (106 Mo) que j’ai fabriqué avec cette technique.
mysql> LOAD DATA INFILE ‘/tmp/testcsv.CSV’ INTO TABLE csvimport FIELDS TERMINATED BY ‘,’ ENCLOSED BY ‘”‘ LINES TERMINATED BY ‘\n’;
Query OK, 1114112 rows affected (10.14 sec)
Records: 1114112 Deleted: 0 Skipped: 0 Warnings: 0
——————–
La même table converti en INNODB
mysql> LOAD DATA INFILE ‘/tmp/testcsv.CSV’ INTO TABLE csvimport FIELDS TERMINATED BY ‘,’ ENCLOSED BY ‘”‘ LINES TERMINATED BY ‘\n’;
Query OK, 1114112 rows affected (27.71 sec)
Records: 1114112 Deleted: 0 Skipped: 0 Warnings: 0
——————–
La même table converti en MyISAM
mysql> LOAD DATA INFILE ‘/tmp/testcsv.CSV’ INTO TABLE csvimport FIELDS TERMINATED BY ‘,’ ENCLOSED BY ‘”‘ LINES TERMINATED BY ‘\n’;
Query OK, 1114112 rows affected (6.31 sec)
Records: 1114112 Deleted: 0 Skipped: 0 Warnings: 0
——————–
Je refais les mêmes tests, mais avec une table surindexée.
ALTER TABLE csvimport ADD INDEX(a), ADD INDEX(b), ADD INDEX(c), ADD INDEX(d);
——————–
MyISAM
mysql> LOAD DATA INFILE ‘/tmp/testcsv.CSV’ INTO TABLE csvimport FIELDS TERMINATED BY ‘,’ ENCLOSED BY ‘”‘ LINES TERMINATED BY ‘\n’;
Query OK, 1114112 rows affected (41.44 sec)
Records: 1114112 Deleted: 0 Skipped: 0 Warnings: 0
——————–
INNODB
mysql> LOAD DATA INFILE ‘/tmp/testcsv.CSV’ INTO TABLE csvimport FIELDS TERMINATED BY ‘,’ ENCLOSED BY ‘”‘ LINES TERMINATED BY ‘\n’;
Query OK, 1114112 rows affected (1 min 4.90 sec)
Records: 1114112 Deleted: 0 Skipped: 0 Warnings: 0
Conclusion
MyISAM est reconnu pour sa rapidité d’insertion. On peut le remarquer avec les résultats. Il est clair qu’il y a un problème si vous avez le temps de vous faire un sandwich lorsque vous importez un CSV de 1000 lignes. Ce problème peut être de plusieurs natures. Il est très difficile de savoir d’où vient le problème sans faire quelques tests. Peut-être que le problème vient des disques, de la carte RAID, du CPU, d’une très mauvaise configuration, etc.. Ça peut être n’importe quoi.
Aug/090
Sujet de conférence ?
Depuis plusieurs années, je squatte un channel IRC de programmeur. On y aborde des sujets de toutes les sortes puisqu’il n’y a pas de thématique précise à notre petite communauté; on est seulement un groupe de personnes qui ont des expertises dans plusieurs domaines variés ou des étudiants en quête de savoir. En septembre, nous avons planifié de nous réunir autour d’une bonne bouffe où quelques un d’entre nous en profiteront pour donner un speech sur des choses que nous maitrisons.
Les sujets sont libres, il n’y a pas de temps limite ni de règles quelconques à respecter. Il faut juste avoir le plaisir de partager notre savoir-faire. J’ai offert de présenter quelque chose, mais plusieurs sujets me font hésiter.
Donc, j’ai installé un petit pluggins de sondage afin de voir quels sujets parmi ceux que j’ai en tête rejoignent le maximum de personnes. Il faut savoir que dans notre petit groupe, plusieurs personnes ne connaissent pas vraiment le SQL, d’autres connaissent la base et d’autres utilisent des bases de données gratuites comme Postgres ou MySQL de facon régulière. C’est un public très varié.
Je vous invite donc à voter sur ce qui vous semble le plus pertinent! Je suis également ouvert aux suggestions.
Jul/090
Design de bases de données qui change souvent
On m’a demandé un jour ce que je recommande pour des designs de databases appelées à être modifiées régulièrement. La personne prévoyait avoir besoin d’ajouter des champs fréquemment pour répondre à ses besoins.

La première interrogation qui m’est venu en tête a été de lui demander pourquoi. Pourquoi a t’il besoin d’ajouter des champs et des tables de manière fréquente ? Pourquoi ne sait-il pas d’avance ce que fera son application ? La réponse est simple: la portion de l’application qui est déjà en ligne est complètement fonctionnelle, étudiée et testée. En fait, l’application est personnalisable et chaque client qui l’achète peut avoir des particularités différentes d’un autre client. D’où le besoin d’ajouter des champs et tables régulièrement.
Il n’y a pas de réponse magique à cette question. Il suffit d’y répondre avec “le gros bon sens”. D’un côté purement relationnel, la normalisation répond bien à ce besoin. Une base de données très normalisée offre une flexibilité exceptionnelle. Si la base de données contient déjà beaucoup d’information, un bon design normalisé peut éviter des scripts de migration qui peuvent être lourds à exécuter.
Le problème avec les bases de données “trop” normalisées est qu’elles sont parfois moins performantes. La flexibilité et la performance font rarement bon ménage. De plus, les requêtes deviennent plus complexes à écrire et maintenir. On s’éloigne également des designs orientés objet qui sont souvent adoptés dans les langages OO comme Java et PHP. C’est un compromis qu’il faut être prêt à faire.
Le défi survient lors de l’ajout d’un champ sur une table déjà existante. Il est facile de créer une dénormalisation qui répond bien à un besoin immédiat, mais crée une pénalité à long terme. C’est un problème auquel je suis régulièrement confronté. Une table qui possédait 10 champs originalement en possède 25 trois ans plus tard. Lorsqu’on se rend compte de l’inefficacité de ce schema, il est souvent complexe et très coûteux de refactoriser la table.
Schématiser la database sur papier (avec Workbench ou d’autres Database Designer) est un bon truc pour identifier des problèmes et les résoudre.
En résumé, n’ayez pas peur de normaliser vos tables, mais n’abusez pas ! Surtout, n’attendez pas qu’il soit trop tard. La quantité de code à modifier peut être une raison valable pour ne pas le faire. Évitez de vous retrouver dans cette situation. Faites-le dès que le besoin se présente!
Jun/090
Comment promouvoir sécuritairement un Slave en Master
Promouvoir un Slave en Master est une opération qu’un DBA doit faire à l’occasion, parfois pour mettre à jour une nouvelle version ou parfois pour se sortir de la m****, car le Master a rendu l’âme. C’est une opération qui n’est pas tellement difficile, mais qu’il ne faut surtout pas négliger.
1. Vérifier la configuration du Slave
Vérifiez que la configuration est semblable à celle du Master, car si vous avez promu le Slave pour vous sortir de la m****, il faut qu’il puisse soutenir la même charge que le Master avait. Gardez en tête que le Slave a originalement été configuré pour être un Slave. Il possède donc des configurations qui lui sont propres. Un bon DBA a probablement pris la peine de mettre le Slave read_only; c’est une des premières options à enlever pour promouvoir. Assurez-vous également que l’ensemble des bases de données soit répliqué, mais surtout la DB mysql pour que les users/password soient les mêmes.
Après avoir promu le Slave en Master, il est toujours possible d’avoir les informations de réplication en tapant : show slave status; Si c’est le cas, vous n’avez pas complété une étape très importante: supprimer complètement la configuration de réplication. Négliger cette étape fait en sorte que votre nouveau Master a toujours la possibilité de se connecter à un autre serveur MySQL pour répliquer les données. Il ne faudrait en aucun cas que le nouveau master commence à répliquer les données d’un autre serveur. Pour éviter que ça se produise, il suffit de faire:
-
CHANGE MASTER TO
-
MASTER_HOST = '',
-
MASTER_USER = '';
2. Les backups
Si le Slave était utilisé pour faire des backups, il est important (le mot est faible) de désactiver tous les crons (ou autres) de backups. Surtout si comme moi, vous utilisez les bonnes vieilles méthodes “old school” comme les copies binaires ou un dump sql à tous les X heures qui nécessitent d’arrêter ou mettre en read only le service. Imaginez que votre nouveau Master s’éteint magiquement à minuit pour faire une copie… oups !
3. La topologie réseau
Il est possible avec MySQL se configurer une réplication via un réseau public. Ça peut paraître bête, mais valider avant tout que les applications qui se connectaient avant puissent toujours se connecter sur le nouveau Master.
Ce sont trois petits points à valider avant d’entreprendre le “switch” Slave – Master. J’encourage tout le monde à le faire même si vous ne prévoyez pas faire de changement. Ce n’est pas très long à faire et ça vous évitera beaucoup de stress si une catastrophe survient.. !
Jun/095
Comment convertir une DB de latin1 à UTF8
Un des défis d’être francophone consiste à bien gérer l’encoding. Je ne connais aucune personne n’ayant jamais eu de problème un jour où un autre. On m’a déjà approché pour trouver la manière la plus efficace de convertir une base de données de Latin1 à UTF8. Voici ce que j’ai trouvé. Ce n’est peut-être pas la manière la plus efficace, mais je n’ai pas eu problème après l’avoir testé. J’ai utilisé cette technique pour convertir une base de données de 115Go et tout c’est bien déroulé.
L’astuce consiste à transformer les chaines de caractères à un format binaire, pour ensuite les reconvertir en UTF8.
-
ALTER DATABASE myDbNameDEFAULT CHARACTER SET utf8;
-
-
ALTER TABLE Groups DEFAULT CHARACTER SET utf8;
-
-
ALTER TABLE Groups MODIFY Domain VARBINARY(64) NULL DEFAULT NULL,
-
MODIFY Type VARBINARY(64) NULL DEFAULT NULL,
-
MODIFY Description VARBINARY(255) NULL DEFAULT NULL,
-
MODIFY Name VARBINARY(200) NULL DEFAULT NULL;
-
-
ALTER TABLE Groups MODIFY Domain VARCHAR(64) CHARACTER SET utf8 NULL DEFAULT NULL,
-
MODIFY Type VARCHAR(64) CHARACTER SET utf8 NULL DEFAULT NULL,
-
MODIFY Description VARCHAR(255) CHARACTER SET utf8 NULL DEFAULT NULL,
-
MODIFY Name VARCHAR(200) CHARACTER SET utf8 NULL DEFAULT NULL;
That’s it ! Super simple et efficace. Un coup qu’une string originalement Latin1 est convertie en format binaire, il n’y a plus de character set ni de collation qui tiennent. Elle devient un format binaire au même titre qu’une image JPG par exemple. Ensuite, on reprend ce format binaire et on réapplique un character set (et la collation par défaut dans mon exemple).
Il faut cependant ne pas négliger un aspect lors de cette conversion. Les caractères Latin1 utilise 1 byte par caractère alors qu’un caractère UTF8 utilisent 3 bytes par caractère. Si l’espace disque est une de vos contraintes, il ne faut pas prendre cette conversion à la légère!