tyoshikawa1106のブログ

- Force.com Developer Blog -

SFDC:Loop処理の効率化について

たまにfor文で次のような処理を書くことがあります。

for (Integer i = 0; i < accounts.size(); i++) {
    // 処理・・・
}


ここのaccounts.size()はループのたびに実行されるので一度変数にセットしてから処理した方が効率的ですよねということを教えてもらいました。


イメージ的にはこんな感じです。

Integer listCnt = accounts.size();
for (Integer i = 0; i < listCnt ; i++) {
    // 処理・・・
}


全然意識していなかった箇所だったので、ほんとうにループのたび実行されるのか次の処理をつくって検証してみました。


開発者コンソールから次の処理で実行します。
f:id:tyoshikawa1106:20130729194507p:plain

このときのログがこんな感じです。
f:id:tyoshikawa1106:20130729194639p:plain


ループのたびにバッチリ実行されました。


もしかしたらaccount.size()のように書いた時には毎回実行されないのかもしれませんが、ひとまずこのような処理だと実行されるみたいです。


せっかくなので実際に変数にセットした場合としていない場合でパフォーマンスに変化があるか、以下の手順で検証してみました。

1. 変数にセットしないケース

f:id:tyoshikawa1106:20130729201755p:plain

結果に差が出やすいように2000件のリストで検証しました。
f:id:tyoshikawa1106:20130729201910p:plain

実行①

f:id:tyoshikawa1106:20130729202007p:plain

実行②

f:id:tyoshikawa1106:20130729202019p:plain

実行③

f:id:tyoshikawa1106:20130729202037p:plain

実行④

f:id:tyoshikawa1106:20130729202054p:plain

実行⑤

f:id:tyoshikawa1106:20130729202108p:plain

実行⑥

f:id:tyoshikawa1106:20130729205433p:plain

実行⑦

f:id:tyoshikawa1106:20130729205438p:plain

実行⑧

f:id:tyoshikawa1106:20130729205445p:plain

実行⑨

f:id:tyoshikawa1106:20130729205449p:plain

実行⑩

f:id:tyoshikawa1106:20130729205453p:plain


Durationが実行時間とのことなのでdoClickのDuration部分で確認できると思います。
※時間の単位は秒ではなく、ミリ秒ぐらいだったと思います。


Durationなどの詳細についてはこちらに詳しい説明があります。

ログインスペクタ
https://na9.salesforce.com/help/doc/ja/code_dev_console_view_system_log.htm

ログインスペクタの使用例
https://na9.salesforce.com/help/doc/ja/code_dev_console_solving_problems_using_system_log.htm#using_evaluate_vf_pages


実行時間をまとめると次のとおりです。
01回目:69.28
02回目:77.89
03回目:59.75
04回目:70.94
05回目:65.69
06回目:68.45
07回目:75.64
08回目:65.84
09回目:63.88
10回目:105.89

多少の誤差は出ましたが、平均すると72.325の時間がかかっています。

2. 変数にセットするケース

f:id:tyoshikawa1106:20130729203109p:plain

実行①

f:id:tyoshikawa1106:20130729204203p:plain

実行②

f:id:tyoshikawa1106:20130729204217p:plain

実行③

f:id:tyoshikawa1106:20130729204229p:plain

実行④

f:id:tyoshikawa1106:20130729204242p:plain

実行⑤

f:id:tyoshikawa1106:20130729204256p:plain

実行⑥

f:id:tyoshikawa1106:20130729204307p:plain

実行⑦

f:id:tyoshikawa1106:20130729204320p:plain

実行⑧

f:id:tyoshikawa1106:20130729204401p:plain

実行⑨

f:id:tyoshikawa1106:20130729204334p:plain

実行⑩

f:id:tyoshikawa1106:20130729204413p:plain

実行結果は次のとおりです。
01回目:26.77
02回目:37.21
03回目:75.25
04回目:30.58
05回目:27.02
06回目:68.02
07回目:34.82
08回目:30.06
09回目:30.24
10回目:30.80
平均すると39.077になりました。


処理時間がだいぶ短縮されました。


実際には大量件数のリストをループさせることはそんなにないと思うので、ここまで大きな差にはならないと思いますが、リスト件数は一度変数にセットして使用した方が効率の良い処理になるみたいです。

補足

もしかすると検証方法が間違ってたり、ただの誤差かもしれないです。
ちなみにApexのループ処理は次のような書き方もできます。

for (Account a : this.accounts) {
    // LOOP処理
}

特別な理由がない場合はこの書き方でループ処理を行う方が、コードも読みやすくなって良いと思います。

ついでなのでこの処理でのパフォーマンスも確認してみました。
f:id:tyoshikawa1106:20130729212552p:plain

実行①

f:id:tyoshikawa1106:20130729213919p:plain

実行②

f:id:tyoshikawa1106:20130729213935p:plain

実行③

f:id:tyoshikawa1106:20130729213939p:plain


・・・思ってたより時間かかるみたいです。


ただ実際にはそれほど気になるレベルではないと思います。大量件数のループ処理をやっていて、パフォーマンスの問題が発生したらちょっと実装方法を検討してみるぐらいじゃないかな・・・と思いました。