2009-10-05 9 views
0

J'ai un processus qui consolide 40+ bases de données à structure identique en une base de données consolidée, la seule différence étant que la base de données consolidée ajoute un champ project_id à chaque table.Obtention de différences d'enregistrement entre 2 tables presque identiques

Afin d'être aussi efficace que possible, j'essaie de ne copier/mettre à jour un enregistrement des bases de données sources vers la base de données consolidée que si elle a été ajoutée/modifiée. Je supprime les enregistrements périmés de la base de données consolidée, puis copie dans des enregistrements inexistants. Pour supprimer obsolètes/enregistrements modifiés J'utilise une requête similaire à ceci:

DELETE FROM <table> 
WHERE NOT EXISTS (SELECT <primary keys> 
        FROM <source> b 
        WHERE ((<b.fields = a.fields>) or 
          (b.fields is null and a.fields is null))) 
    AND PROJECT_ID = <project_id> 

Cela fonctionne pour la plupart, mais l'une des tables de la base de données source a plus de 700 000 dossiers, et cette requête prend plus d'une heure à compléter.

Comment rendre cette requête plus efficace?

+0

Avez-vous un index sur * champs *? –

Répondre

2

Utilisez des horodatages ou, mieux encore, des tables d'audit pour identifier les enregistrements qui ont changé depuis l'heure «X», puis sauvegardez le temps «X» lorsque la dernière synchronisation a démarré. Nous utilisons cela pour les flux d'interface.

+0

Ces éléments ont-ils été ajoutés à la base de données/aux tables? IE: ajouté un champ last_updated à chaque table et une table audit_table à chaque base de données? Malheureusement, je ne peux pas modifier le schéma des bases de données sources car elles proviennent d'un produit fournisseur. – aasukisuki

+0

Pouvez-vous ajouter une table d'audit? – DVK

+0

Techniquement, je pourrais ajouter une table d'audit ou même un champ à chaque table à utiliser comme horodatage, mais le processus du fournisseur n'ajoutera jamais rien à la table d'audit, ni ne remplira le champ d'horodatage lors de la modification. – aasukisuki

0

Vous pouvez essayer avec filtre LEFT JOIN NULL:

DELETE  <table> 
FROM  <table> t 
LEFT JOIN <source> b 
     ON (t.Field1 = b.Field1 OR (t.Field1 IS NULL AND b.Field1 IS NULL)) 
     AND(t.Field2 = b.Field2 OR (t.Field2 IS NULL AND b.Field2 IS NULL)) 
     --//... 
WHERE  t.PROJECT_ID = <project_id> 
     AND b.PrimaryKey IS NULL --// any of the PK fields will do, but I really hope you do not use composite PKs 

Mais si vous comparez toutes les colonnes non-PK, votre requête va souffrir. Dans ce cas, il est préférable d'ajouter un champ UpdatedAt TIMESTAMP (comme le suggère DVK) sur les deux bases de données que vous pourriez mettre à jour avec le déclencheur AFTER UPDATE, votre procédure de synchronisation serait beaucoup plus rapide, car vous créez un index incluant PK et colonne UpdatedAt.

0

Vous pouvez réorganiser l'instruction WHERE; il a quatre comparaisons, mettre le plus susceptible d'échouer en premier.

Si vous pouvez modifier légèrement les bases de données/l'application, et que vous aurez besoin de le faire à nouveau, un champ binaire qui dit «mis à jour» pourrait ne pas être un mauvais ajout.

0

Je réécris habituellement des requêtes comme celle-ci pour éviter le ... Not In est horrible pour la performance, bien que Not Exists s'améliore à ce sujet.

Vérifiez cet article, http://www.sql-server-pro.com/sql-where-clause-optimization.html

Ma suggestion ...

Sélectionnez votre colonne pkey dans une table de travail/température, ajouter une colonne (drapeau) par défaut int 0 non nul, et l'indice de la pkey colonne. Marquer l'indicateur = 1 si l'enregistrement existe dans votre sous-requête (beaucoup plus vite!). Remplacez votre sous-sélection dans votre requête principale par un existant où (sélectionnez pkey de la table tentable où flag = 0)

Ce qui fonctionne est de pouvoir créer une liste de valeurs 'inexistantes' qui peuvent être utilisées de manière inclusive d'un ensemble tout compris.

Voici notre ensemble complet. {1,2,3,4,5}

Voici le jeu existant {1,3,4}

Nous créons notre table de travail de ces deux ensembles (techniquement une jointure externe gauche) (enregistrement: existe)

{1: 1, 2: 0, 3: 1, 4: 1, 5: 0}

Notre ensemble de 'non' des dossiers existants

{2,5} (Sélectionnez * d'où flag = 0)

Notre produit ... et beaucoup plus rapide (index!)

{1,2,3,4,5} dans {2,5} = {2,5}

{1,2 , 3,4,5} pas dans {1,3,4} = {2,5}

Cela peut se faire sans une table de travail, mais son utilisation facilite la visualisation de ce qui se passe.

Kris

Questions connexes