メモってこ!

IT関連系のあれやこれ

データインポートバッチのパフォーマンス改善

  • 書いたきっかけ
  • 前提事項
  • やったこと
  • 調べたこと
  • そのほか

 

■書いたきっかけ

バッチ作成で痛い目を見たので備忘録。

VB.NETでなくC#で作ったのが悪いのか。。

VB.NETで動いていたパフォーマンスをなぜか発揮できない。paizaのスキルチェックの感じ、多分C#にも原因がある)

 

■パフォ-マンス改善

ネックはやはり大量データ取り込み処理時。

一度DBか取り込んだ後は楽(ここは案件のDB性能のおかげ)。

 

■前提事項

環境(DB性能、メモリなど)は優秀。一度のバッチ実行で数万件の取り込み・出力が問題なくできる想定の環境。

逆に数十万件以降は、想定されていない。

物理テーブルのワークテーブル経由であれば、数十万とはいかずに百何万もクラッシュせずに処理に耐えれるスペックではあったが(DataTableは場合によってはクラッシュする)、バッチのパフォーマンスが追い付かず時間がとてもかかる(といっても一晩かかるレベルではない)。

バッチの大まかな動きは以下↓

ファイル読み込み→文字列チェック

→ワークテーブルへ一時取り込み(Microsoftルールで決まっている複数Insert件数上限値が1000件のため1000件ずつくりかえし発行)

→データ加工→データ登録

 

■やったこと

色々調べて採用したもの

 

SQL文生成時は文字列からStringBuilder採用に

stringにSQL文を入れて、SQL発行するのをやめることに。

見やすいけど、数ミリ秒改善(塵積で、劇的改善)

×sql = "SELECT * FROM XXXX";
〇StringBuilder str = new StringBuilder();
str.Append("SELECT * FROM XXXX");

 

〇INSERT文は一括で

すでに採用済み。

INSERT INTO XXXX(id, name, age) 
VALUES(1, 'hanako', 21, ' okinawa')(2, 'tarou', 23)
(3, 'kenta', 25)...

 

〇List型宣言時、あらかじめ枠の確保をする

効果は実感できてないが、簡単だったので追記。

var a = new List<int>(1000);

 

〇データ保持にList型ではなく、配列の使用

調べた記事によっては意見が分かれるが、今回はパフォーマンス改善の実感あり。

 

〇コミットはまとめて1回

バッチ処理が途中で終了する可能性を考慮し、

トランザクションを要所要所で張っていた。

負荷分散のため、SQL発行回数とコミット回数、それぞれ変更可能としていたが、

最低限の1回にしたほうがトータル的にパフォーマンスが良かった。

(調べた記事では件数によって、パフォーマンスが変わる、一定件数ではパフォーマンスに変化なしとの検証結果だったので、環境要因が大きいかもしれない)

 

■調べたこと

 

enumを使用しない

取り込み項目の可視化のため、enumを採用していた。

このenumをint変換する処理が、理論的にはコストがかかる想定だったが

enumをintに変換するので、あらかじめintで書いたほうが良いという考え。

調べると検証記事あり)、パフォ-マンスに影響なし。

 

〇多重ループの並列化

概要はよかったが、並列化なので使いこなせず。

 

以下は、調べた記事↓

docs.sakai-sc.co.jp

 

kagamihoge.hatenablog.com

 

www.fujitsu.com

 

www.fenet.jp

 

qiita.com

 

qiita.com

 

■そのほか

・DB設計は大事

→PK,インデックス考える

 

・列ストアインデックス

→データ読み込みが改善するらしいが、データを取り込むバッチの前には

パフォーマンスの敵