Ouvrir la navigation secondaire

Ce billet a plus de deux ans. S'il contient des informations techniques elles sont peut être obsolètes.

Précédent Stack front-end moderne avec Django
Suivant Pixel de référence CSS

Migrer un projet Django de MySQL à PostgreSQL

La documentation de Django est explicite :

PostgreSQL is recommended, because we’re PostgreSQL fans

Au-delà du mimétisme béat ou du prosélytisme, force est de constater que les avantages sont nombreux et les promesses d’intégration avec Django alléchantes.

Vous voulez davantage de motifs pour droper MySQL :

En vérité, la chose que vous voulez vraiment est un contrat ACID honoré par votre RDBMS.

Alors direction Converting from other Databases to PostgreSQL qui pointe vers une solution de Lanyrd Django-friendly et donc parfaitement adaptée à notre besoin : MySQL to PostgreSQL Converter.

Vérifier les fuseaux horaires de MySQL et de PostgreSQL

mysqldump n’exporte pas les fuseaux horaires par défaut. Par conséquent votre dump ne contiendra aucune information relative aux time zones.

Si vous êtes dans un cas simple, PostgreSQL s’en accomode très bien :

If no time zone is stated in the input string, then it is assumed to be in the time zone indicated by the system’s timezone parameter, and is converted to UTC using the offset for the timezone zone.

Vous devez alors vérifier que MySQL et PostgreSQL sont configurés dans le même fuseau horaire :

mysql> SELECT @@global.time_zone, @@session.time_zone, @@system_time_zone;
+--------------------+---------------------+--------------------+
| @@global.time_zone | @@session.time_zone | @@system_time_zone |
+--------------------+---------------------+--------------------+
| SYSTEM             | SYSTEM              | CEST               |
+--------------------+---------------------+--------------------+
1 row in set (0.00 sec)

postgres=# SELECT current_setting('TIMEZONE');
 current_setting 
-----------------
 Europe/Paris
(1 row)

Si vous êtes dans un cas plus complexe, il vous faudra creuser du côté de l’option --tz-utc de mysqldump.

Tester la migration avec un schéma vierge

Pour commencer je suis parti en local d’une base MySQL vierge et j’ai joué toutes les migrations. C’est une bonne occasion de vérifier que tout se déroule bien et, le cas échéant, de fixer ce qui doit l’être.

Une fois que toutes les migrations sont passées avec succès, vous pouvez dumper le schéma MySQL et tenter un import de celui-ci dans PostgreSQL.

$ mysqldump --compatible=postgresql --default-character-set=utf8 -r dump.mysql -u USER_NAME DB_NAME
$ python db_converter.py dump.mysql dump.psql
$ psql -U USER_NAME DB_NAME -f dump.psql

Si tout s’est bien passé, vous êtes certain que votre schéma est bon. Il y a très peu de chances pour que ça échoue mais c’est une bonne mise en bouche :)

Tester la migration avec des données

Les choses sérieuses commencent.

Il vous faut rapatrier un dump de production. J’ai eu la chance d’avoir à migrer une base de donnée de volume modeste. Démerden Sie sich si vous avez des pétaoctets de dump :D

Il est l’heure de vérifier la cohérence de votre base de données et éventuellement d’insulter MySQL pour son intégrité référentielle en bois et ses contraintes vers des tables fantômes.

En général c’est pendant cette étape qu’on transpire. La plupart des bogues se fixent par de nouvelles migrations ou par des requêtes SQL en dur à base de SET FOREIGN_KEY_CHECKS quand il n’y a pas d’autre choix si l’intégrité a été compromise.

On tente à nouveau l’import-export :

$ mysqldump --compatible=postgresql --default-character-set=utf8 -r dump.mysql -u USER_NAME DB_NAME
$ python db_converter.py dump.mysql dump.psql
$ psql -U USER_NAME DB_NAME -f dump.psql

Et bingo quand ça marche ;)

Dernières étapes

Et c’est pas fini !

Il faudra encore corriger au besoin les raw SQL queries et les extra(), par exemple si vous avez utilisé un GROUP_CONCAT. On se plaint souvent des ORMs mais je peux vous dire que c’est très utile pendant une migration de base.

Si vous passez en mode atomique, pensez à supprimer les appels aux API de transaction dépréciées pour éviter que l’on vous raise des TransactionManagementError à la figure.

Puis lancez votre build et corrigez les tests qui plantent.

Une fois que tout roule, vous pouvez répéter l’opération sur les serveurs de staging, et enfin sur vos serveurs de production.

Bonne chance ! Je reste à l’écoute de vos commentaires si vous avez des conseils.