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:
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 UPDATE
name__, sinon c'est un INSERT
name__. La logique pour cela peut être facilement réalisée dans un composant tMap
name__.
Dans ce travail, nous souhaitons transférer INSERT OR UPDATE
dans une table de base de données contenant des données préexistantes:
Et nous souhaitons y ajouter les données suivantes:
Le travail consiste à insérer les nouvelles données dans un composant tHashOutput
afin 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 tHashInput
et directement dans un tMap
name__. Un autre composant tHashInput
est utilisé pour exécuter une requête paramétrée sur la table:
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 tMap
name__.
Ceci est alors configuré en tant que INNER JOIN
pour rechercher les enregistrements devant être UPDATED
avec les rejets du INNER JOIN
à insérer:
Ces sorties sont ensuite transmises aux composants tMySQLOutput
et UPDATE
ou INSERT
si nécessaire. Et enfin, lorsque le sous-job principal est terminé, nous avons commit
les modifications.
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.
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.
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.
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é.
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
Recommander quelques choses simples:
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?