Synchroniser les données de la table entre les bases de données

J’ai une table qui enregistre sa ligne d’insertion / mise à jour des horodatages sur un champ.

Je souhaite synchroniser les données de cette table avec une autre table sur un autre serveur de firebase database. Deux serveurs de firebase database ne sont pas connectés et la synchronisation s’effectue dans un sens (maître / esclave). L’utilisation de table sortingggers n’est pas appropriée

Mon stream de travail:

  • J’utilise un paramètre global last_sync_date et une table de requête maître pour les enregistrements modifiés / insérés
  • Exporter les lignes résultantes en XML
  • Analyser le XML et la table de mise à jour Slave à l’aide de mises à jour et d’insertions

La complexité du problème augmente lorsqu’il s’agit d’enregistrements supprimés de la table principale. Pour attraper les enregistrements supprimés, je pense que je dois maintenir une table de journal pour les enregistrements précédemment insérés et utiliser SQL “NOT IN”. Cela devient un problème de performance lorsqu’il s’agit de grands ensembles de données.

Quel serait un stream de travail alternatif traitant de ce scénario?

Il semble que vous ayez besoin d’une file d’attente transactionnelle.

Comment cela fonctionne est simple. Lorsque vous mettez à jour la firebase database principale, vous pouvez envoyer un message au courtier de messages (quelle que soit la mise à jour), qui peut accéder à un nombre quelconque de files d’attente. Chaque firebase database esclave peut avoir sa propre queue et, en raison de l’ordre de conservation de la queue, le processus devrait finalement se synchroniser correctement (paradoxalement, c’est en quelque sorte comment la plupart des SGBDR effectuent la réplication en interne).

Considérez la file de messages comme une sorte de firebase database de liste de modifications ou de listes de correctifs SCM. Pour l’essentiel, c’est la même chose (ou à peu près la même chose) que les instructions SQL envoyées au maître doivent être éventuellement répliquées vers les autres bases de données. Ne craignez pas de perdre des messages, car la plupart des files d’attente de messages prennent en charge la durabilité et les transactions.

Je vous recommande de regarder spring-amqp et / ou spring-integration, surtout que vous avez étiqueté cette question avec spring-batch .

Basé sur vos commentaires:

  • Voir Spring Integration: http://static.springsource.org/spring-integration/reference/htmlsingle/ .
  • Google SEDA. Que vous choisissiez cette voie ou non, vous devez connaître les files de messages, car elles vont de pair avec le traitement par lots.
  • RabbitMQ a un bon diagramme d’image du fonctionnement de la messagerie
  • Le contenu de votre message peut être la ligne entière et si c’est un CRUD, UPDATE, DELETE. Vous pouvez utiliser n’importe quel format (par exemple, JSON. Voir l’intégration printanière sur les recommandations).
    • Vous pouvez même envoyer les instructions SQL directes sous forme de message!

Par ailleurs, votre préoccupation de NOT IN être un problème de performance n’est pas très bonne, car il existe une pléthore de solutions de contournement, mais étant donné que vous ne voulez pas faire de choses spécifiques à la firebase database (comme les déclencheurs et la réplication), j’ai toujours l’impression que votre file d’attente est votre meilleure option.

EDIT – Route non MQ

Puisque je t’ai donné du fil à retordre pour poser cette question, je continuerai d’essayer de t’aider. En plus de la file de messages, vous pouvez créer une sorte de fichier XML similaire à celui que nous essayions auparavant. LA CARACTÉRISTIQUE CRITIQUE dont vous avez besoin dans le schéma est une colonne CREATE TIMESTAMP de votre firebase database principale afin que vous puissiez effectuer le traitement par lots pendant que le système est opérationnel (sinon, vous devrez l’arrêter). Maintenant, si vous allez dans cette voie, vous voudrez SELECT * WHERE CREATE_TIME < ? est inférieur à l'heure actuelle. En gros, vous n’obtenez que les lignes lors d’un instantané.

Maintenant, sur l’autre firebase database pour supprimer, vous allez supprimer des lignes par inner joining sur une table d’ID mais avec != (C’est-à-dire que vous pouvez utiliser JOINS au lieu de slow NOT IN ). Heureusement, vous n'avez besoin que de tous les ids pour la suppression et non des autres colonnes. Les autres colonnes peuvent être utilisées avec un delta en fonction de la colonne de l'horodatage de la mise à jour (pour mettre à jour et créer une insertion).

Jetez un coup d’œil à Oracle GoldenGate :

Oracle GoldenGate est un progiciel complet permettant la réplication de données dans des environnements de données hétérogènes. L’ensemble de produits offre des solutions à haute disponibilité, une intégration de données en temps réel, une capture de données à changement transactionnel, une réplication de données, des transformations et une vérification entre des systèmes d’entreprise opérationnels et analytiques.

SymmesortingcDS :

SymmesortingcDS est un logiciel open source destiné à la réplication de bases de données multimaître, à la synchronisation filtrée ou à la transformation sur le réseau dans un environnement hétérogène. Il prend en charge plusieurs abonnés avec une réplication de données asynchrone bidirectionnelle ou dans une seule direction.

Réplicateur jonquille :

Daffodil Replicator est un outil Java pour la synchronisation, la migration et la sauvegarde de données entre différents serveurs de firebase database.

Pourquoi ne pas simplement append une colonne TIMESTAMP indiquant la dernière heure de mise à jour / insertion / suppression? Ajoutez ensuite une colonne supprimée – c’est-à-dire. marquer la ligne comme supprimée au lieu de la supprimer immédiatement immédiatement. Supprimez-le après avoir exporté l’action de suppression.

Si vous ne pouvez pas modifier l’utilisation du schéma dans une application existante:

Ne pouvez-vous pas utiliser de déclencheurs? Que diriez-vous d’une deuxième table (“cachée”) qui sera remplie à chaque insertion / mise à jour / suppression et qui constituerait le contenu du prochain fichier d’exportation xml à générer? C’est un concept courant: un tableau d’historique (ou “log”): il aurait sa propre colonne d’identification progressive qui peut être utilisée comme marqueur d’exportation.

Question très intéressante.

Dans le cas où j’avais assez de RAM pour charger tous les identifiants des tables maître et esclave pour les différencier.

Si les identifiants de la table principale sont séquentiels, vous pouvez conserver un ensemble de plages complètes dans la table principale (avec tous les identifiants utilisés, sans espaces, comme 100,101,102,103).

Pour rechercher les ID supprimés sans les charger tous dans la mémoire, vous pouvez exécuter une requête SQL pour compter le nombre d’enregistrements avec id >= full_region.start and id <= full_region.end pour chaque région remplie. Si le résultat de la requête == (full_region.end - full_region.end) + 1 cela signifie que tous les enregistrements de la région ne sont pas supprimés. Sinon, divisez la région en 2 parties et effectuez la même vérification pour les deux (dans de nombreux cas, un seul côté contient les enregistrements supprimés).

Après une certaine plage (environ 5000, je pense), il sera plus rapide de charger tous les identifiants présents et de vérifier s'ils sont absents avec Set.

Il est également conseillé de charger tous les identifiants dans la mémoire pour un lot de petites régions (10 à 20 enregistrements).

Créez une table d’historique pour la table à synchroniser (en gros, un duplicata de cette table, avec éventuellement quelques champs supplémentaires) et insérez la ligne entière à chaque fois que quelque chose est inséré / mis à jour / supprimé dans la table active.

Écrire un travail par lots de spring pour synchroniser les données sur la machine esclave en fonction des champs supplémentaires de la table d’historique

J’espère que cela t’aides..

Une option potentielle pour autoriser les suppressions dans votre stream de travail actuel:

Dans le cas où la ressortingction de déclencheur est limitée aux déclencheurs avec des références dans plusieurs bases de données, une solution possible dans votre stream de travail actuel consisterait à créer une table d’assistance dans votre firebase database Master pour stocker uniquement les identificateurs uniques des lignes supprimées (ou toute autre clé unique vous permettent de supprimer le plus efficacement possible vos lignes supprimées).

Ces identifiants doivent être insérés par un déclencheur sur votre table principale lors de la suppression.

En utilisant le même mécanisme que votre insertion / mises à jour, créez une tâche à la suite de vos insertions et mises à jour. Vous pouvez exporter votre table d’assistance au format XML, comme vous l’avez noté dans votre stream de travail actuel.

Cette tâche supprime simplement les lignes de la table esclave, puis toutes les données de la table d’assistance une fois la tâche terminée. Consignez toutes les erreurs de la tâche afin de pouvoir résoudre ce problème, car il n’y a pas de piste d’audit.

Si votre firebase database contient un journal de vidage de transaction, envoyez-le simplement.

C’est possible avec MySQL et cela devrait être possible avec PostgreSQL.

Je suis d’accord avec un autre commentaire – cela nécessite l’utilisation de déclencheurs. Je pense qu’une autre table devrait contenir l’historique de vos déclarations SQL. Voir cette réponse à propos de l’utilisation des événements étendus 2008 … Ensuite, vous pouvez obtenir l’intégralité du code SQL et stocker la requête de résultat dans la table d’historique. C’est à vous de choisir si vous voulez le stocker en tant que requête mysql ou mssql.

Voici ma prise. Avez-vous vraiment besoin de gérer cela? Je suppose que l’esclave sert à des fins de rapport. Donc, la question que je voudrais poser est de savoir comment devrait-il être mis à jour? Est-ce correct si les données datent d’un jour? Prévoyez-vous un rafraîchissement nocturne?

Si tel est le cas, oubliez ce processus de synchronisation en ligne, téléchargez les tableaux complets. expédiez-le au mysql et chargez-le par lots. Le temps de traitement peut être beaucoup plus rapide que vous ne le pensez.