2010-10-29 6 views
1

Je travaille sur un projet de migration de données assez volumineux qui implique le déplacement de données entre des serveurs et différents schémas d'enregistrements actifs. L'ensemble de la migration prend littéralement des jours.Rails/MySQL écriture paresseuse sur .save (mises à jour/écritures)

Comment puis-je implémenter une solution de mise en cache où mon code de migration Ruby lorsqu'il appelle la méthode d'enregistrement Active Record écrit dans un cache (qui met alors à jour la base de données MySQL de manière asynchrone). La mémoire n'est pas une limitation. Toutes les solutions de mise en cache dans Rails semblent bien traiter les lectures de chargement/requête, mais les écritures sont quelque chose sur lequel je n'ai pas trouvé grand-chose.

Est-ce quelque chose qui est facilement réalisable dans MySQL en accordant des paramètres de configuration? Ou existe-t-il une solution de cache pour Ruby/Rails?

J'ai regardé Delayed Job bien qu'il ne s'agisse pas d'un calque de cache (et il n'est pas apparent que quelqu'un l'ait utilisé pour des écritures paresseuses dans la base de données). J'ai regardé les tables de stockage MEMORY dans MySQL mais bien sûr, elles ne sont pas écrites sur le disque. Memcached n'est pas construit pour cela.

S'il vous plaît aviser!

Répondre

0

Si vous souhaitez simplement migrer les données, pourquoi n'utilisez-vous pas les procédures stockées directement depuis la base de données? Je suis sûr que c'est plus efficace que d'utiliser le calque ActiveRecord

+0

Les changements de schéma sont assez méchants et impliqués. Je ne peux pas le faire au niveau SQL purement. –

2

Qu'est-ce que vous voulez dire, comment puis-je insérer rapidement des données sans attendre que MySQL mette à jour tous ses index pour que ma migration de base de données ne prenne pas de temps?

Il y a deux solutions pour accélérer INSERTs de base de données, mais ils ont des inconvénients sérieux ainsi:

J'ai trouvé INSERT DELAYED être utile. Il déclenche votre requête et renvoie immédiatement. MySQL met en attente plusieurs de ces requêtes pendant quelques secondes et les applique lorsqu'il n'y a rien d'autre à faire. C'est génial pour la journalisation et autres. L'inconvénient est que si votre base de données tombe en panne, la file d'attente des instructions INSERT est perdue.

Une autre option est la suivante:

  • Créer le nouveau schéma de base de données - sans indices!
  • Migrez vos données, INSÉRER. C'est plus rapide car MySQL n'aura pas à mettre à jour vos index lors de l'insertion.
  • Lorsque toutes les données sont migrées, ajoutez vos index.

L'inconvénient ici est que vos données peuvent ne pas être cohérentes. par exemple. votre source db a des valeurs en double que vous ne voulez pas dans votre cible db.

Une troisième option que je recommande fortement est l'utilisation de SQL pur au lieu de ActiveRecord. Si vous devez migrer un million d'enregistrements, ActiveRecord doit allouer 1 million de fois une instance de votre modèle ActiveRecord, exécuter la requête, puis disposer à nouveau de l'objet.

La création et l'élimination de ces objets ne prennent pas beaucoup de temps, mais si vous le faites 1 million de fois, cela s'additionne.

Si vous êtes malchanceux, vous aurez une fuite de mémoire et l'ancien objet ne sera pas libéré de la mémoire. Cela va consommer beaucoup de mémoire et pourrait éventuellement planter votre processus de rubis.Coupez l'intermédiaire et utilisez du SQL brut lorsque cela est possible. Utiliser ruby ​​pour effectuer le SQL n'est pas un problème, mais gardez-le aussi simple que possible.