数千万件のデータロードを行う場合、ApplyMapを使用すると処理に時間がかかるため、Joinに切り替えて大幅に短縮したことがある。
ではどれくらい違うのか実験してみた。
#Mapping Load ~ ApplyMapのスクリプト
Mapping Loadは変換テーブルの作成、ApplyMapでMapping tableを呼び出し変換する。
想像すればわかるが、ロードする時に1行単位で変換するから遅い。
スクリプトは以下のとおり。
LET vRap = Now();
Map_Customer:
Mapping
LOAD *
FROM
Customer.qvd(qvd);
LET vRap1 = interval(Now() - '$(vRap)');
Transaction:
LOAD *,
ApplyMap('Map_Customer',customer_id) as customer_name
FROM
Transaction.qvd(qvd);
LET vRap2 = interval(Now() - '$(vRap)');
#Left Join Load ~ のスクリプト
Left JoinはSQLのJoin同様だから説明は割愛。
1行単位で変換するということではないが、やはり大量データのJoinは時間がかかる。
スクリプトは以下のとおり。
LET vRap = Now();
Transaction:
LOAD * FROM
Transaction.qvd(qvd);
LET vRap1 = interval(Now() - '$(vRap)');
Left Join(Transaction)
LOAD *
FROM
Customer.qvd(qvd);
LET vRap2 = interval(Now() - '$(vRap)');
#結果比較
今回のスクリプトは100,000,000件のTransactionに対して、Customer 1,000,000の変換(あるいはJoin)の処理である。
元データはここで作成したものだ。
- ApplyMap
- Mapping Load -> 2sec
- TransactionのLoad(ApplyMap) -> 159sec
- Left Join
- TransactionのLoad -> 60sec
- Join -> 44sec
結果を見れば、Joinのほうが速いね(1.5倍強)。特にデータ件数が多くなるとそれだけ差が出る。
よくLoad文の中で複数のApplyMapを使用しているケースがあるが、これは相当遅くなることになるんだろう。
しかしながら、ApplyMapでは変換できない場合の値を指定できるのは便利。Joinで行った場合は、nullの場合を埋める処理のためにもう一度Loadしなければならない。
その場合、ApplyMapのない場合のLoadは60secだから、ApplyMapを使用すた場合と全体の処理時間はほぼ同じということになる。
どちらがいいとは一概には言えないが、上記の結果を踏まえて、トランザクションテーブルとマスタとの整合性がある場合はJoinが良さそう..ということになるかな。