Mysql et les locks indésirables
J’utilise Mysql fréquemment pour de petites applications web avec peu de fréquentations. Je n’ai donc jamais rencontré de souci de performances ou de concurrence d’accès.
Par contre, j’ai réalisé une petite application qui collecte les temps d’exécution de traitements quotidien et calcule ensuite des agrégats.
N’ayant à ma disposition que cette base de données, je l’ai naturellement utilisé sans vraiment me poser de question.
Cette application tourne tous les jours sans souci. Ce n’est qu’aujourd’hui que j’avais besoin de mettre à jour une table qu’a ma grande surprise, mon update était interminable.
Je regarde donc les processus en cours et je découvre qu’il est bloqué :
show processlist; +-------+----------+---------------------+------------+---------+------+----------------+-----------------------+ | Id | User | Host | db | Command | Time | State | Info | +-------+----------+---------------------+------------+---------+------+----------------+-----------------------+ | 86100 | statuser | localhost | statkenobi | Query | 5 | Locked | update session | [...] +-------+----------+---------------------+------------+---------+------+----------------+-----------------------+
Ma mise à jour est bloquée par une requête. Ah bah zut alors, moi qui pensait que les lectures n’avaient pas d’impacts sur les mises à jour.
Je me met donc en quête d’un équivalent du « locking table ‘matable’ for access » qu’on retrouve sous Teradata, mais je ne trouve rien qui corresponde à empêcher le lock d’être positionné.
Il y a bien une commande lock sous Mysql mais elle sert à en ajouter, ce qui n’est pas mon besoin actuel.
J’étais pourtant persuadé que MySQL avait bien un moteur transactionnel inclut par défaut depuis MySQL 4.0 et supérieur. Après vérification le moteur transactionnel est bien inclu dans la version de Mysql que j’utilise.
L’utilisation du moteur transactionnel dépend du choix du moteur qui a été réalisé lors de la création de la table. Dans mon cas, la table a été crée avec le moteur MyISAM, le comportement constaté est donc normal.
Si j’avais voulu un comportement différent, c’était à moi d’utiliser le moteur InnoDB.
Il est donc nécessaire que je refasse un peu le point sur le moteur choisi en fonction des tables :
select engine, count(table_name) from information_schema.tables where table_schema = 'statkenobi' and table_type = 'BASE TABLE' group by engine; +--------+-------------------+ | engine | count(table_name) | +--------+-------------------+ | InnoDB | 15 | | MyISAM | 15 | +--------+-------------------+
Je constate que j’avais fait le choix lors de la création de définir les références (nom des traitements, enchainement entre eux, etc) avec le moteur MyISAM.
Pour moi une référence n’étant pas vouée à évoluer beaucoup, mais est beaucoup requetée, cela me paraissait judicieux. Et Pour les faits qui eux sont mis à jour en continu j’avais choisi le moteur InnoDB.
Il s’avère que les références dans mon cas changent plus que je l’aurais imaginé, et cela remet donc en cause le choix du moteur. Heureusement, MySQL permet de changer de moteur très facilement.
Pour passer de MyISAM à InnoDB, il suffit de lancer la commande suivante :
alter table 'matable' engine=INNODB;
Le changement de moteur a bien entendu résolu mon problème.