Talendを使用してデータをSQLServerデータベースにロードします。
私の仕事の最も弱い点はデータ処理ではなく、データベースの実効負荷であり、17行/秒より速くないようです。
面白い点は、5つのジョブを同時に起動でき、それらはすべて17行/秒で読み込まれることです。
この遅さを説明できるものと、速度を改善するにはどうすればよいですか?
ありがとう
新しい情報:
デスクトップとサーバー間の転送速度は約1Mバイトです
私の仕事は10000ごとにコミットします
SQL Server 2008R2を使用しています
そして、私の仕事に使用するスキーマは次のようなものです。
データベースINSERT OR UPDATE
メソッドは、データベースがすべてのコミットを一度にバッチ処理できず、行ごとに実行する必要があるため、非常にコストがかかります(ACIDトランザクションは、挿入を試みて失敗した場合、すべてのコミットを強制的に実行するためです。このコミットの他のレコードも失敗します)。
代わりに、大規模な一括操作の場合、データベースにコミットを渡してから2つのトランザクションをデータベースに送信する前に、レコードを挿入するか更新するかを事前に決定することが常に最善です。
この機能を必要とする一般的なジョブは、INSERT OR UPDATEd
となるデータをアセンブルしてから、データベーステーブルに既存の主キーを照会します。主キーがすでに存在する場合は、これをUPDATE
として送信できます。それ以外の場合は、INSERT
です。このためのロジックは、tMap
コンポーネントで簡単に実行できます。
このジョブでは、既存のデータを含むデータベーステーブルにINSERT OR UPDATE
したいデータがいくつかあります。
そして、それに次のデータを追加したいと思います。
このジョブは、新しいデータをtHashOutput
コンポーネントにスローすることで機能するため、同じジョブで複数回使用できます(単にメモリに配置するか、大規模なインスタンスではディスクにキャッシュできます)。
これに続いて、1ロットのデータがtHashInput
コンポーネントから読み取られ、直接tMap
に読み込まれます。別のtHashInput
コンポーネントを使用して、テーブルに対してパラメーター化されたクエリを実行します。
Talendおよびパラメーター化されたクエリに関するこのガイド が役立つ場合があります。ここから、返されたレコード(つまり、データベース内のレコードのみ)がtMap
へのルックアップとして使用されます。
次に、これはINNER JOIN
として構成され、挿入するINNER JOIN
からの拒否を含むUPDATED
である必要があるレコードを検索します。
これらの出力は、必要に応じてtMySQLOutput
コンポーネントをUPDATE
またはINSERT
に分離するために流れます。そして最後に、メインサブジョブが完了すると、変更をcommit
します。
@ydaetskcoRの答えは、理論的な観点(Insertが必要な行をそれらからUpdateに分割する)で完璧であり、小さなデータセット(数千行)に役立つ実用的なETLソリューションを提供すると思います。
すべてのデータがTalendマシンとDBサーバーの間を行き来するため、ETLでは、行を更新する必要があるかどうかを判断できるようにルックアップを実行するのはコストがかかります。
ETLからELTに渡す必要のあるレコードが数十万または数百万に達した場合、@ Balazs Gunicsから提案されているように、データを一時(ステージング)テーブルにロードし、SQLを使用して操作します。
この場合、データをロードした後(INSERT = fastのみ、BULK LOADコンポーネントを使用するとさらに高速)、一時テーブルと宛先テーブルの間にLEFT OUTER JOINを発行して、すでに存在する行(更新が必要)と他の行を分割します。 。
このクエリは、挿入する必要のある行を提供します。
SELECT staging.* FROM staging
LEFT OUTER JOIN destination ON (destination.PK = staging.PK)
WHERE destination.PK IS NULL
これは、更新する必要のある行です。
SELECT staging.* FROM staging
LEFT OUTER JOIN destination ON (destination.PK = staging.PK)
WHERE destination.PK IS NOT NULL
これはETLよりも桁違いに高速ですが、データを操作するにはSQLを使用する必要がありますが、ETLではJavaを使用できます。すべてのデータがTalendサーバーに取り込まれるため、多くの場合、ローカルマシンでデータを前処理してJava(データをクリーンアップおよび検証するため))、joinを使用してデータをロードするDBで起動する最初のステップが一般的です。正しい方法で。
これがELTJOBのスクリーンショットです。
行を挿入するステージングテーブルを実行する必要があります。
このステージングテーブルに基づいて、t * SQLrowを使用してDELETEクエリを実行します。
DELETE FROM target_table
WHERE target_table.id IN (SELECT id FROM staging_table);
したがって、更新したい行はもう存在しません。
INSERT INTO target_table
SELECT * FROM staging_table;
これにより、すべての新規/変更された行が移動します。
DB2サーバーへのデータのロードでも同じ問題が発生していました。私もコミットを10000に設定しましたが、(同じコンポーネントオプション画面で)バッチするオプションを選択すると、パフォーマンスが劇的に向上しました。コミットとバッチを20000に移動すると、ジョブは5時間から2分未満になりました。
このパフォーマンスの問題がどこから発生するのかを見つけました。
INSERT OR UPDATE
を実行しますが、単純なINSERT
に置き換えると、速度は最大4000行/秒になります。
許容できるペースのように見えますか?
とにかく、私はINSERT OR UPDATE
が必要なので、行き詰まっていると思います。
同じ問題が発生し、ターゲットテーブルにインデックスを定義することで解決しました。
通常、ターゲットテーブルには、主キーであるためインデックスが付けられたidフィールドがあります。したがって、それとのあらゆる種類の結合は問題なく機能します。ただし、フラットファイルからの更新は一部のデータフィールドによって行われるため、各更新ステートメントは全表スキャンを実行する必要があります。
上記は、INSERT
で高速に動作し、INSERT OR UPDATE
で低速になる理由も説明しています。
いくつかの簡単なことをお勧めします:
挿入は更新よりも桁違いに速いというメモに基づくと(4000対17 /秒)-DBインデックスを確認する必要があるようです。更新パラメータに一致するインデックスを追加すると、更新が大幅に高速化される可能性があります。もちろん、このインデックスは挿入を少し遅くする可能性があります。
更新クエリのクエリ実行プランを調べて、インデックスを使用しているかどうかを確認することもできます。 クエリ実行プランを取得するにはどうすればよいですか?