Apex CPU time limit exceeded 対策

スポンサーリンク

Apex CPU time limit exceededとは

Apexで負荷の高い実装をすると、こういうエラーが発生します。

System.LimitException: Apex CPU time limit exceeded

CPUに負荷かかかっているために起こるエラーです。
今回は、このエラーを回避するためのベストプラクティスについてです。

CPU時間の対象となるもの/ならないもの

ナレッジによるとCPU時間の対象となるもの、ならないものはこのようになります。

CPU時間の対象となるもの

  • すべてのApexコード
  • Apexで公開されているライブラリ関数
  • ワークフロー

対象とならないもの(CPU時間としてカウントされていないもの)

  • データベース操作
  • SOSL
  • コールアウト操作

つまり、対象とならないものを駆使すれば、CPU時間を軽減させることができるわけです。

タイムアウト削減のためのコーディング

では、実際にCPU時間を削減するためのコーディング方法を具体例を交えて。

マップベースクエリを使用する

まずは、SOQLの取り方について。

リストを取得し、IDとデータを取得する方法について。

// SOQLをリストにセット
List<Account> lstacc=[Select Id, Name from Account limit 10000];
Set<Id> setIds=new Set<Id>();
for(Account a:lstacc){
    //リストから1件ずつIdをセット
    setIds.add(a.id);
}

こちらのコード実行でのパフォーマンスはこんな感じ。

Listをループした際のCPU処理時間

次は同じ処理内容で、やり方を変えたコード。

// SOQLをマップに入れる
Map<id,account> aMap = new Map<id,account>([Select Id,Name from Account limit 10000]);

// マップからリストを取得
List accList = aMap.values();

// マップからIDリストを取得
Set accIds = aMap.keySet();

こちらのパフォーマンスはこんな感じ。

マップベースクエリを使用した際のCPU処理時間

横幅のスケールが違うので若干分かりづらいですが、「APEX_CODE」ってところがCPU時間の対象となるところなので、マップベースクエリにした方がかなり処理時間が軽減されているのが分かります。

集計関数を使用する

SOQLで集計できるものは、集計関数を使用して集計しましょう。

まずは、集計関数を使わないでAPEXで集計した場合。

List<Account> lstacc=[Select Id, NumberOfEmployees from Account];
Integer num = 0;
for(Account a:lstacc){
    num = num + a.NumberOfEmployees;
}

パフォーマンスはこう。
集計関数を使用しない場合のCPU処理時間

次は集計関数を使って同じようにカウント。

// 集計関数でカウント
List<AggregateResult> lstar = [SELECT SUM(NumberOfEmployees) sumemp FROM Account];
Integer num = Integer.valueOf(lstar[0].get('sumemp'));

パフォーマンスはこう。
集計関数を使用した場合のCPU処理時間

こちらもAPEC_CODEが軽減されていますね。

ガバナ制限に抵触しなければ、DBでやらせられるものはDBに任せるというスタンスでいいかと思います。

不要なループを減らす

これは当然ですね。
無駄なループが多くなると、その分ステップ数が増えるため、CPU時間が増えてしまいます。

まとめ

  • Apexコード、ワークフローがCPU時間に考慮される
  • CPU時間の削減のためには、マップベースクエリ、SOQLの集計関数などを使用する

コメント