CDIパフォーマンスチューニングー第1弾

<h1> はじめに

Informaticaのデータ連携ツール（Cloud Data Integration以下略称でCDI）は処理能力が高いですが、様々な原因で偶にパフォーマンスが出せないケースがあるのではないでしょうか。
本文章は第１弾として、パフォーマンスに影響がある代表的な要素を分析し、それに対応する対策と上手なデータ連携フローの作り方をご紹介したいと思います。

これからも他のパフォーマンスに関する記事を投稿しますので、ぜひフォローをお願いします！

<h1> まとめ

以下はパフォーマンスに影響がある代表的な要素の一部です。
・ソース
・ターゲット
・マッピングの連携部品
　　・フィルター
　　・ジョイナー
　　・ロックアップ
　　・式
  
:::note info
パフォーマンスに影響がある要素は様々ですが、今回はよく使われている連携部品から一部を抜粋してご紹介します。
:::

<h2> ソース

先ず、知るべき前提としては、Informatica CDIがフラットファイルからの読み取りが最速です。
ソースにはフラットファイルを使う場合、ソースがパフォーマンスに影響がある可能性が非常に低いで、他の原因を探しましょう。
そうではない場合に、パフォーマンスのボトルネックの原因はソースなのかどうかを判別ため、以下の手段をご利用できます。

<h6>1. ソースをフラットファイルに切り替える。

ジョブの実行時間が大幅短縮できれば、ソースの問題だと明確になるでしょう。

<h6>2. 読み取りテスト用のマッピングを作る。

本来のマッピングをコピーして、ソースと必要な部品だけを残して、他の部品を全部除いた上で、実行時間を確認しましょう。時間があまり変わらない場合、パフォーマンスに影響するのはソースではありません。

<h6>3.クエリ文をテストする。

データベースやデータウェアハウスがソースとなる場合に、マッピングのセッションログからクエリ文をコピーして、DBクエリツールにそのクエリ文を実行して、レコードを取るまでの時間をご確認ください。時間があまり変わらない場合、パフォーマンスに影響するのはソースではありません。

<h2> ターゲット

ソースと同じようにフラットファイルへの書き込みが最速です。
ターゲットはフラットファイルを使う場合、パフォーマンスのボトルネックになる可能性が非常に低いので、他の原因を探しましょう。

そうではない場合に、パフォーマンスのボトルネックの原因はターゲットなのかどうかを判別ため、以下の手段をご利用できます。

<h6>1.ターゲットをフラットファイルに切り替える。

ジョブの実行時間が大幅短縮できれば、ソースの問題だと明確になるでしょう。

<h6>2.セッションログを読み解ける。

マッピングの実行ログに各トランスフォーメーションの実行時間明細を記録していますので、ターゲットへのWrite時間を確認して、Read時間や他の部品の実行時間より長い時間を使うと、ボトルネックの原因になるかもしれません。

<h2>マッピングの連携部品

<h3>フィルター

データフローに投入するデータ量を絞ることで、処理時間を短縮することができます。
<h6>1.ソース部品にフィルターを設定する。

DBやDWHからデータを読み込む場合に、ソースプロパティにデータ量を制御することで、最小限のデータ量を処理する。
<h6>2.フィルター部品を使う。

フィルター部品を使うことで、どんなタイプのソースでもデータをフィルターすることができます。ソースと近い位置で早い段階でデータ量を絞りましょう。

<h3>ジョイナー

結合変換は、中間結果を保持するために実行時に追加のスペースを必要とするため、パフォーマンスが低下する可能性がある。
<h6>1.マスタグループのキーの重複を下げる。

マスタグループに結合キーとなるデータの重複を可能な限り少なめにする。結合する際に、ジョイナーの部品が毎回１００件のユニックなキーをつかんで、処理を行います。もし重複があれば、もっと多い件数のデータをつかむことが必要となり、処理が遅くなる可能性があります。

<H6>2.マスタグループの件数を抑える。

結合する際に、詳細グループの全ての行を持ってマスタグループのキーと比較を行います。マスタグループの行が少なければなるほど、比較時間が短いです。

<h6>3.DBやDWHでジョンする。

ジョイナー部品よりDBやDWHの性能が良いので、可能であれば、DBやDWHにテーブルを結合した後、その結果をデータフローに持ってきます。そして、ノーマルジョンは外部ジョンイよりパフォーマンスが良いです。

<h6>4.ジョインする前にソートする。

事前ソートしないと、ジョイナー部品が自動的にデータをソートするので、それが時間かかりますし、より多いスペース容量が必要となり、パフォーマンスに影響することとなります。なので、ジョイナー部品の前に、ソーター部品を入れましょう。

<h6>5.大きいデータを最後にジョインにする。

複数のジョインがある場合に、一番大きいデータセットを一番遅いタイミングでジョインにしましょう。

<h6>6.ルックアップを使いましょう。

アウトジョインが多い場合とジョインするデータ量が多い場合に、ルックアップ部品に切り替えましょう。
ジョインとロックアップの動作イメージは下図のように。
![Image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2986164/52a63a52-cb7d-6171-c8e9-eac5a44c8fe4.png)
![Image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2986164/4c4c0dd6-7489-33db-958e-778f1c7ff45b.png)
ルックアップはソート不要で、キャッシュで処理するので、より良いパフォーマンスでデータを取れます。

<h3>ルックアップ

<h6>1.一致条件：任意の行を返す

条件を満たすデータを取ったら、最初のレコードと最後のレコードを決めるため、全てのレコードにIndexをかけます。任意の行を返すことにすると、Indexをかけずにいつも最初の行を返します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2986164/63552ac7-8373-33a2-8470-5f05eef0884a.png)

<h6>2.ルックアップキャッシュを有効にする。

このオプションをONにすることで、ランタイムの間に、データがキャッシュに一時保存され、処理が早くなります。OFFにすると、レコード毎にSQLを飛ばしてデータを取ります。
ただ、必ずキャッシュONの処理が早いとは言えません。キャッシュを作成する時間とレコードごとにSQLを飛ばす処理を天秤にかける。レコードごとにSQLを飛ばししたほうが早い件数の場合は、キャッシュを作成しない方式を選択します。
Lookup先にちゃんとINDEXが貼ってあれば、1ミリ秒/件で応答するので、1000件でも1秒で終わる計算になります。キャッシュを生成するのに10秒くらいかかってるのであれば、OFFの方を選択したほうが断然早いことになります。

<h6>3.Lookup先のテーブルにIndexを作成する。

DBの検索と同じように、Indexを付けるであれば、検索が早くなります。

<h3>式

式の部品を１つずつ抜けて、時間が大幅短縮できればその式がネックになるので、それに対してチューニングしましょう。
<h6>1.アグリゲータに計算式を少なめにする。

例えば、下記の①より②の処理が早いです。
```ruby:書き方①
SUM(Col_A)+SUM(Col_B)
```
```ruby:書き方②
SUM(Col_A+Col_B)
```

<h6>2.変数フィールドを活用する。

同じトランスフォーメーションに同じ計算が複数がある場合、変数フィールドを使いましょう。変数フィールドは１回だけ計算されて、このトランスフォーメーションに保持されます。出力フィールド使えると、毎回再計算することとなりますので、無駄な処理が発生します。

<h6>3.文字列より数字の処理は速い。

文字列より数字の処理が速いです。例えば、大量データに対して、Employee_IDとEmployee_NameをLookupする場合に、数字にあるEmployee_IDに対して条件しましょう。

<h6>4.ファンクションより演算子を使う。

例えば、下記の①より②の処理が早いです。
```ruby:書き方①
concat( CONCAT( CUSTOMERS.FIRST_NAME, ' ') CUSTOMERS.LAST_NAME)
```
```ruby:書き方②
CUSTOMERS.FIRST_NAME || ' ' || CUSTOMERS.LAST_NAME
```

<h6>5.IIF条件を少なめにする。

例えば、下記の①より②の処理が早いです。
```ruby:書き方①
IIF( FLG_A = 'Y' and FLG_B = 'Y' AND FLG_C = 'Y', VAL_A + VAL_B + VAL_C, 
  IIF( FLG_A = 'Y' and FLG_B = 'Y' AND FLG_C = 'N', VAL_A + VAL_B , 
    IIF( FLG_A = 'Y' and FLG_B = 'N' AND FLG_C = 'Y', VAL_A + VAL_C, 
      IIF( FLG_A = 'Y' and FLG_B = 'N' AND FLG_C = 'N', VAL_A , 
        IIF( FLG_A = 'N' and FLG_B = 'Y' AND FLG_C = 'Y', VAL_B + VAL_C, 
          IIF( FLG_A = 'N' and FLG_B = 'Y' AND FLG_C = 'N', VAL_B , 
            IIF( FLG_A = 'N' and FLG_B = 'N' AND FLG_C = 'Y', VAL_C, 
              IIF( FLG_A = 'N' and FLG_B = 'N' AND FLG_C = 'N', 0.0, 
)))))))
```
```ruby:書き方②
IIF(FLG_A='Y', VAL_A, 0.0)+ IIF(FLG_B='Y', VAL_B, 0.0)+ IIF(FLG_C='Y', VAL_C, 0.0)
```

<h1>最後に

Informaticaデータ連携エンジンの最強の力を発揮するため、上記のコツを常に念頭に置いて、念入りながらデータ連携を開発しましょう。

今後第２弾も期待しましょう！