2014-04-14 10 views
8

Ich benutze Talend, um Daten in eine SQL-Server-Datenbank zu laden.Wie lade ich Daten schneller mit Talend und SQL-Server

Es scheint, dass der schwächste Punkt meines Jobs nicht die Datenverarbeitung ist, sondern die effektive Last in meiner Datenbank, die nicht schneller als 17 Zeilen/Sek. Ist.

Der komische Punkt ist, dass ich 5 Jobs in der gleichen Zeit starten kann, und sie werden alle mit 17 Zeilen/Sek.

Was könnte diese Langsamkeit erklären und wie könnte ich die Geschwindigkeit verbessern?

Dank

Neue Informationen:

Die Übertragungsgeschwindigkeit zwischen meinem Desktop und dem Server ist über 1MByte

verpflichtet Meine Aufgabe alle 10 000

ich SQL Server verwenden 2008 R2

An d das Schema I für meine Jobs verwenden ist wie folgt:

enter image description here

+2

Hat Talend eine "Bulk Load", "Bulk Insert" oder "Bulk Copy" Funktion? – RBarryYoung

+0

Und überprüfen Sie Ihre Hardware. 17 ist erbärmlich sogar für ein single-threaded individuelles sql-Statement-Ding. Vielleicht ist Ihr Server eher wie ein Mobiltelefon oder ein Laptop. Wie hoch ist die Latenz zwischen der App und dem Server? – TomTom

+0

Langsamkeit könnte aufgrund eines beliebigen Faktors, wie Netzwerkgeschwindigkeit zwischen Talend und Ihre DB, die Art, wie Job in Talend geschrieben wird, Talend hat Massenladekomponenten für SQL-Server, aber mit normalen SQL Server-Komponenten die Leistung, die Sie erleben, ist sehr schlecht . Ich würde vorschlagen, Sie erwähnen mehr Details wie, was SQL ist, die Sie laufen, gibt es irgendeine Art der Verarbeitung auf Talend Seite, was Talend Komponenten Sie in Job usw. verwenden. – garpitmzn

Antwort

0

ich gefunden habe, wo diese Performance-Problem kommen Form.

Ich mache eine INSERT OR UPDATE, wenn ich es durch eine einfache INSERT ersetze, geht die Geschwindigkeit bis zu 4000 Reihen/s.

Scheint es wie ein akzeptables Tempo?

Wie auch immer, ich brauche meine INSERT OR UPDATE so, ich denke, ich stecke fest.

+1

Ich bin nicht mit Talend vertraut, aber kannst du in zwei separate INSERT/teilen UPDATE Schritte/Jobs? Einer, der ganz Einfügungen vornimmt, der andere nur Aktualisierungen vornimmt (für Datensätze, die Sie vor dem Update geprüft haben) –

+0

Was ist mit der Verwendung von "Einfügen oder Aktualisieren auf doppelten Schlüssel oder eindeutigen Index"? Dies führt den MySQL-Befehl INSERT ... ON DUPLICATE KEY INSERT aus. Leider habe ich (noch) keinen Weg gefunden, dies auf mehr als einer Zeile gleichzeitig zu machen, aber zumindest sollte es viel schneller als "Einfügen oder Aktualisieren" ausgeführt werden, da keine Lesevorgänge erforderlich sind. – fool4jesus

13

Datenbank INSERT OR UPDATE Methoden sind unglaublich teuer, da die Datenbank nicht alle Commits gleichzeitig abarbeiten kann und sie Zeile für Zeile ausführen muss (ACID-Transaktionen erzwingen dies, weil sie versucht haben, eine Einfügung durchzuführen und dann alle die anderen Datensätze in diesem Commit würden ebenfalls fehlschlagen).

Bei großen Massenoperationen empfiehlt es sich immer vorzubestimmen, ob ein Datensatz eingefügt oder aktualisiert wird, bevor das Commit an die Datenbank übergeben und dann zwei Transaktionen an die Datenbank gesendet werden.

Ein typischer Job, der diese Funktionalität benötigt, würde die Daten, die INSERT OR UPDATEd sein sollen, zusammenstellen und dann die Datenbanktabelle nach den vorhandenen Primärschlüsseln abfragen. Wenn der Primärschlüssel bereits vorhanden ist, können Sie diesen als UPDATE senden, andernfalls ist es ein INSERT. Die Logik dafür kann leicht in einer Komponente tMap durchgeführt werden.

Insert or Update Job Example

In dieser Arbeit haben wir einige Daten, die wir INSERT OR UPDATE in einer Datenbanktabelle wünschen, dass einige bereits vorhandene Daten enthält:

Initially loaded data

Und wir möchten folgende Daten hinzufügen es:

Insert or Update data

Der Job arbeitet, indem er die neuen Daten in eine tHashOutput Komponente wirft, so dass er mehrmals im selben Job verwendet werden kann (er legt ihn einfach in den Speicher oder in großen Fällen kann er ihn auf der Festplatte zwischenspeichern).

Im Anschluss wird eine Datenmenge von einer tHashInput Komponente ausgelesen und direkt in eine tMap. Eine weitere tHashInput Komponente verwendet wird, um eine parametrisierte Abfrage für die Tabelle auszuführen:

Parameterised Query Parameter Config

Sie this guide to Talend and parameterised queries nützlich finden können. Von hier aus werden die zurückgegebenen Datensätze (also nur diejenigen, die bereits in der Datenbank sind) als ein Lookup für die tMap verwendet.

Dies wird dann als INNER JOIN konfigurieren, um die Datensätze zu finden, die UPDATED mit dem Spuck vom INNER JOIN sein muß eingefügt werden:

tMap configuration

Diese Ausgänge fließen dann nur tMySQLOutput Komponenten UPDATE zu trennen oder INSERT nach Bedarf. Und schließlich, wenn der Haupt-Sub-Job abgeschlossen ist, wir commit die Änderungen.

+0

Danke, ich schaue hinein und kehre mit meiner Lösung (und der Zeit) zurück – Krowar

+0

Ich baue gerade einen schnellen Job, um Ihnen zu zeigen, wie es gemacht werden könnte. Über das Hochladen von Screenshots, damit es Ihnen helfen kann. – ydaetskcoR

+0

Dieser Job sieht gut aus, aber mit einer Staging-Tabelle können Sie das gleiche tun, denke ich. Überprüfe meine Antwort. –

0

Basierend auf Ihrer Notiz, dass Inserts eine Größenordnung schneller als Updates (4000 vs 17/sec) sind - Es sieht so aus, als ob Sie Ihre DB-Indizes betrachten müssen. Das Hinzufügen eines Index, der mit Ihren Update-Parametern übereinstimmt, könnte Ihre Updates erheblich beschleunigen. Natürlich kann dieser Index Ihre Einsätze ein wenig verlangsamen.

Sie können auch den Abfrageausführungsplan für Ihre Aktualisierungsabfrage anzeigen, um festzustellen, ob Indizes verwendet werden. How do I obtain a Query Execution Plan?

+1

Das eigentliche Problem, dass Sie Ihre UPSERTS nicht auflösen können. Sie müssen also jeweils 1 Zeile einfügen/aktualisieren. –

+1

Wahr. Aber die 17/sec-Update-Leistung selbst kann leicht durch den richtigen Index erhöht werden, ohne die Komplexität zu erhöhen. – user1452132

0

Sie sollten eine Staging-Tabelle erstellen, in die Sie die Zeilen einfügen.

Basierend auf dieser Staging-Tabelle führen Sie eine DELETE-Abfrage mit t * SQLrow.

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

Die Zeilen, die Sie aktualisieren wollten, sind nicht mehr vorhanden.

INSERT INTO target_table 
SELECT * FROM staging_table; 

Dadurch werden alle neuen/geänderten Zeilen verschoben.

+2

Es ist eine nette Idee, aber Sie verlieren ACID Transaktionen auf diese Weise. Was passiert, wenn Ihr Job nach dem Löschen der Zeilen aus irgendeinem Grund ausfällt? Damit dies funktioniert, MÜSSEN Sie den Löschvorgang vor dem Einfügen festschreiben, damit Sie bei einem Auftragsfehler kein Rollback ausführen können. Wenn Sie sich nicht darum kümmern, dann ist es ein einfacheres und ich denke, schöner, dies zu tun, aber ich würde immer ACID-Transaktionen für solche Dinge wollen. – ydaetskcoR

+0

Mit Oracle können Sie die Zusammenführung verwenden: http://psoug.org/reference/merge.html –

3

Ich denke, dass die Antwort von @ydaetskcoR aus teorischer Sicht perfekt ist (teile Zeilen, die Insert von denen zu Update brauchen) und gibt dir eine funktionierende ETL - Lösung, nützlich für kleine Datenmengen (einige tausend Zeilen).

Das Durchführen der Suche, um entscheiden zu können, ob eine Zeile aktualisiert werden muss oder nicht, ist teuer in ETL, da alle Daten zwischen der Talend-Maschine und dem DB-Server hin- und hergehen.

Wenn Sie zu einigen hundert oder sogar Millionen von Datensätzen gelangen, müssen Sie von ETL zu ELT übergehen: Sie laden Ihre Daten einfach in eine temporäre Tabelle, wie von @Balazs Gunics empfohlen, und dann verwenden Sie SQL manipuliere es.

In diesem Fall werden Sie nach dem Laden Ihrer Daten (nur INSERT = schnell, noch schneller mit BULK LOAD-Komponenten) einen LEFT OUTER JOIN zwischen der temporären Tabelle und dem Ziel ausgeben, um die Zeilen zu teilen, die bereits vorhanden sind) und die Anderen.

Diese Abfrage wird auf die Zeilen, die Sie einfügen müssen geben:

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

Das andere die Zeilen, die Sie aktualisieren müssen:

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

Diese Größenordnungen als ETL wird schneller sein, ABER Sie müssen SQL verwenden, um Ihre Daten zu bearbeiten, während Sie in ETL Java verwenden können, da ALLE Daten zum Talend-Server übertragen werden. Daher ist es häufig ein erster Schritt auf dem lokalen Rechner, die Daten in Java vorzuverarbeiten (um es zu säubern und zu validieren) und dann feuern Sie es in der Datenbank ab, in der Sie es verwenden, um es zu laden der richtige Weg.

Hier sind die ELT JOB Screenshots. INSERT or UPDATE ELT job

How to distinguish between rows to insert or update

0

ich das gleiche Problem Laden von Daten in einem DB2-Server mit wurde. Ich hatte auch das Commit auf 10000 gesetzt, aber sobald ich die Option zum Batch (auf der gleichen Komponente Optionen Bildschirm) ausgewählt Leistung drastisch verbessert. Als ich den Commit und den Batch auf 20000 verschoben habe, ging der Job von 5 Stunden auf unter 2 Minuten.