5
votes

Migrer `int` vers` bigint` dans PostgresQL sans aucun temps d'arrêt?

J'ai une base de données qui va connaître le problème d'épuisement des entiers auquel Basecamp a été confronté en novembre. J'ai plusieurs mois pour savoir quoi faire.

Existe-t-il une solution proactive et sans temps d'arrêt pour migrer ce type de colonne? Si oui, qu'est-ce que c'est? Sinon, est-ce juste une question de temps d'arrêt et de migration de la colonne quand je le peux?

Est cet article est-il suffisant , en supposant que je dispose de plusieurs jours / semaines pour effectuer la migration maintenant avant que je ne sois obligé de le faire lorsque je suis à court d'identifiants?


0 commentaires

3 Réponses :


7
votes

Utilisez la réplication logique .

Avec la réplication logique, vous pouvez avoir différents types de données en primaire et en veille.

Copiez le schéma avec pg_dump -s , modifiez les types de données sur la copie, puis démarrez la réplication logique.

Une fois toutes les données copiées, basculez l'application pour utiliser la mise en veille.

Pour un temps d'arrêt nul, l'application doit pouvoir se reconnecter et réessayer, mais c'est toujours une exigence dans un tel cas.

Vous avez besoin de PostgreSQL v10 ou supérieur pour cela, et votre base de données ne doit pas modifier le schéma, car DDL n'est pas répliqué.


1 commentaires

Merci pour l'aide, les modifications et les réponses multiples!



2
votes

Créez une copie de l'ancienne table mais avec un champ ID modifié. Créez ensuite un déclencheur sur l'ancienne table qui insère de nouvelles données dans les deux tables. Enfin, copiez les données de l'ancienne table vers la nouvelle (ce serait une bonne idée de distinguer les données de pré-déclenchement avec post-déclenchement par exemple par id si elle est séquentielle). Une fois que vous avez terminé, changez de table et supprimez l'ancienne.

Cela nécessite évidemment deux fois plus d'espace (et de temps pour la copie) mais fonctionnera sans aucun temps d'arrêt.


0 commentaires

2
votes

Une autre solution pour les bases de données antérieures à la v10 où toutes les transactions sont courtes :

  • Ajoutez une colonne bigint au tableau.

  • Créez un déclencheur BEFORE qui définit la nouvelle colonne chaque fois qu'une ligne est ajoutée ou mise à jour.

  • Exécutez une série de mises à jour qui définissent la nouvelle colonne à partir de l'ancienne où elle EST NULL . Gardez ces lots courts afin de ne pas verrouiller longtemps et de ne pas trop vous bloquer. Assurez-vous que ces transactions s'exécutent avec session_replication_role = replica afin qu'elles ne déclenchent pas de déclencheurs.

  • Une fois toutes les lignes mises à jour, créez un index unique CONCURRENTLY sur la nouvelle colonne.

  • Ajoutez une contrainte unique UTILISANT l'index que vous venez de créer. Ce sera rapide.

  • Effectuez le changement:

    BEGIN;
    ALTER TABLE ... DROP oldcol;
    ALTER TABLE ... ALTER newcol RENAME TO oldcol;
    COMMIT;
    

    Ce sera rapide.

Votre nouvelle colonne n'a aucun NOT NULL défini. Cela ne peut pas être fait sans un long verrou invasif. Mais vous pouvez ajouter une contrainte de vérification IS NOT NULL et la créer NOT VALID . C'est assez bon, et vous pouvez le valider plus tard sans interruption.

S'il y a des contraintes de clé étrangère, les choses se compliquent un peu. Vous devez les supprimer et créer des clés étrangères NOT VALID dans la nouvelle colonne.


0 commentaires