web-dev-qa-db-fra.com

comment charger des données plus rapidement avec Talend et SQL Server

J'utilise Talend pour charger des données dans une base de données SQL Server.

Il semble que le point le plus faible de mon travail ne soit pas le traitement de données, mais la charge effective dans ma base de données, qui n’excède pas 17 lignes/s.

Le point amusant est que je peux lancer 5 tâches en même temps, et elles se chargeront toutes à 17 tr/s.

Qu'est-ce qui pourrait expliquer cette lenteur et comment pourrais-je améliorer la vitesse?

Merci

Nouvelles informations:

La vitesse de transfert entre mon ordinateur et le serveur est d'environ 1 Mo.

Mon travail s’engage tous les 10 000

J'utilise SQL Server 2008 R2

Et le schéma que j'utilise pour mes emplois est le suivant:

enter image description here

8
Krowar

Les méthodes de la base de données INSERT OR UPDATE sont incroyablement coûteuses, car la base de données ne peut pas traiter tous les commits en une seule opération et doit les traiter ligne par ligne (les transactions ACID le forcent ce commit échouerait également).

Au lieu de cela, il est toujours préférable de déterminer à l'avance si un enregistrement doit être inséré ou mis à jour avant de transmettre la validation à la base de données, puis d'envoyer 2 transactions à la base de données.

Un travail typique qui avait besoin de cette fonctionnalité assemblerait les données qui devaient être INSERT OR UPDATEd, puis interrogerait la table de base de données pour les clés primaires existantes. Si la clé primaire existe déjà, vous pouvez l'envoyer sous la forme UPDATEname__, sinon c'est un INSERTname__. La logique pour cela peut être facilement réalisée dans un composant tMapname__.

Insert or Update Job Example

Dans ce travail, nous souhaitons transférer INSERT OR UPDATE dans une table de base de données contenant des données préexistantes:

Initially loaded data

Et nous souhaitons y ajouter les données suivantes:

Insert or Update data

Le travail consiste à insérer les nouvelles données dans un composant tHashOutputafin de pouvoir les utiliser plusieurs fois dans le même travail (il les met simplement en mémoire ou, dans de grandes instances, peut les mettre en cache sur le disque).

Suite à cela, beaucoup de données sont extraites d'un composant tHashInputet directement dans un tMapname__. Un autre composant tHashInputest utilisé pour exécuter une requête paramétrée sur la table:

Parameterised QueryParameter Config

Vous pouvez trouver ce guide de Talend et des requêtes paramétrées utile. À partir de là, les enregistrements renvoyés (de sorte que seuls ceux de la base de données sont déjà utilisés) sont utilisés pour rechercher le tMapname__.

Ceci est alors configuré en tant que INNER JOIN pour rechercher les enregistrements devant être UPDATEDavec les rejets du INNER JOIN à insérer:

tMap configuration

Ces sorties sont ensuite transmises aux composants tMySQLOutputet UPDATEou INSERTsi nécessaire. Et enfin, lorsque le sous-job principal est terminé, nous avons commitles modifications.

15
ydaetskcoR

Je pense que la réponse de @ydaetskcoR est parfaite d’un point de vue théorique (divisez les lignes qui ont besoin d’être insérées de celles à mettre à jour) et vous fournit une solution de travail ETL utile pour les petits ensembles de données (quelques milliers de lignes).

Effectuer la recherche pour pouvoir déterminer si une ligne doit être mise à jour ou non est coûteux en ETL, car toutes les données vont et viennent entre la machine Talend et le serveur de base de données.

Lorsque vous atteignez des centaines de milliers ou même des millions d'enregistrements, vous devez passer d'ETL à ELT: vous ne chargez vos données que dans une table temporaire (intermédiaire) comme suggéré par @Balazs Gunics, puis vous utilisez le code SQL pour le manipuler.

Dans ce cas, après avoir chargé vos données (uniquement INSERT = rapide, encore plus rapide avec les composants BULK LOAD), vous émettrez un LEFT OUTER JOIN entre la table temporaire et celle de destination pour diviser les lignes déjà présentes (besoin de mise à jour) et les autres. .

Cette requête vous donnera les lignes que vous devez insérer:

SELECT staging.* FROM staging
LEFT OUTER JOIN destination ON (destination.PK = staging.PK)
WHERE destination.PK IS NULL

Cet autre les lignes que vous devez mettre à jour:

SELECT staging.* FROM staging
LEFT OUTER JOIN destination ON (destination.PK = staging.PK)
WHERE destination.PK IS   NOT    NULL

Ce sera des ordres de grandeur plus rapides que l'ETL, MAIS vous devrez utiliser SQL pour exploiter vos données, tandis que dans l'ETL, vous pouvez utiliser Java car TOUTES les données sont transférées sur le serveur Talend; il est donc souvent courant de commencer par le premier pas. machine locale pour pré-traiter les données en Java (pour les nettoyer et les valider), puis les lancer sur la base de données où vous utilisez join pour les charger correctement.

Voici les captures d'écran de ELT JOB. INSERT or UPDATE ELT job

How to distinguish between rows to insert or update

4
RobMcZag

Vous devez créer une table intermédiaire dans laquelle vous insérez les lignes.

Sur la base de cette table de transfert, vous effectuez une requête DELETE avec t * SQLrow.

DELETE FROM target_table
WHERE target_table.id IN (SELECT id FROM staging_table);

Ainsi, les lignes que vous souhaitez mettre à jour n'existent plus.

INSERT INTO target_table 
SELECT * FROM staging_table;

Cela déplacera toutes les lignes nouvelles/modifiées.

0
Balazs Gunics

Je rencontrais le même problème lors du chargement des données sur un serveur DB2. Moi aussi, le commit était défini à 10 000, mais une fois que j’ai sélectionné l’option de traitement par lots (sur l’écran des mêmes options de composant), les performances ont été considérablement améliorées. Lorsque j'ai déplacé le commit et le batch à 20000, le travail est passé de 5 heures à moins de 2 minutes.

0
dwberry

J'ai trouvé d'où venait ce problème de performance.

Je fais un INSERT OR UPDATE, si je le remplace par un simple INSERT, la vitesse peut atteindre 4000 lignes/s.

Cela vous semble-t-il un rythme acceptable?

Quoi qu'il en soit, j'ai besoin de mon INSERT OR UPDATE alors, je suppose que je suis coincé.

0
Krowar

J'ai eu le même problème et l'ai résolu en définissant un index sur la table cible.

Habituellement, la table cible a un champ id qui est sa clé primaire et donc indexé. Donc, toutes sortes de liens avec cela fonctionneraient très bien. Mais la mise à jour à partir d'un fichier plat est effectuée à l'aide de certains champs de données. Chaque instruction de mise à jour doit donc effectuer une analyse complète du tableau.

Ce qui précède explique également pourquoi cela fonctionne rapidement avec INSERT et devient lent avec INSERT OR UPDATE

0
jutky

Recommander quelques choses simples:

  1. Si possible/raisonnable, passez de ETL à ELT.
  2. Configurez un processus CDC et gérez uniquement les modifications. Selon la base de données et les besoins, cela peut être géré (a) directement sur la base de données, (b) via la fonctionnalité automatisée Talend (nécessite un abonnement), (c) manuellement via SQL (jointure externe complète) et une fonction Java personnalisée qui génère un hachage MD5 ou (d) manuellement via SQL (jointure externe complète) et le composant tAddCRCRow.
  3. Si possible, chargez plusieurs tables simultanément.
  4. Si possible, utilisez le chargement en bloc pour les tables.
  5. Parfois, une approche claire et claire est une approche acceptable et plus rapide que la vérification des mises à jour.
0
David Cohn

Selon votre note, les insertions sont un ordre de grandeur plus rapide que les mises à jour (4000 vs 17/s) - Il semble que vous deviez examiner vos index de base de données. L'ajout d'un index correspondant à vos paramètres de mise à jour pourrait accélérer considérablement vos mises à jour. Bien sûr, cet index peut ralentir un peu vos insertions. 

Vous pouvez également consulter le plan d'exécution de la requête pour votre requête de mise à jour pour voir si elle utilise des index. Comment obtenir un plan d'exécution de la requête?

0
user1452132