【Salesforce】System.LimitException: Apex CPU time limit exceeded

【Salesforce】System.LimitException: Apex CPU time limit exceeded

SalesforceのApexコードを触っていると、このようなエラーが発生しました。

System.LimitException: Apex CPU time limit exceeded

ApexのCPUタイムリミットを超えました、とのこと。

処理時間が長いと発生するエラーで、同期処理は10秒、非同期処理は60秒がリミットとなっています。

https://developer.salesforce.com/docs/atlas.ja-jp.206.0.apexcode.meta/apexcode/apex_gov_limits.htm

発生した処理を見てみると、このような状態になっていました。

List<Account> accountList;
List<Contact> contactList;

// 取引先を取得する
accountList = [select Id from Account];
// 取引先責任者を取得する
contactList = [select Id, AccountId from Contact];

// 取引先でループ
for(Account acc : accountList){

    // 取引先責任者でループ
    for(Contact con : contactList){
    
        // 取引先に紐づく取引先責任者の場合、処理を行う
        if(acc.Id = con.AccountId){
        
            // 処理
        }
    }
}

実際に行っている処理とは異なりますが、ループの中でループを行い、紐付けを行っています。

この状態では[取引先の数] * [取引先責任者の数]だけ処理を行うことになります。

レコード数が少なければ問題ないのですが、レコード数が増えるほど膨大な数の処理を行うことになります。

結果、今回のようなエラーが発生するわけですね。

取引先と取引先責任者のように参照や主従の紐付けがある場合は、SOQLの時点で振り分ける方が処理が少なくなります。

List<Account> accountList;

// 取引先と取引先責任者を取得する
accountList = [select Id, (select Id, AccountId from Contacts) from Account];

// 取引先でループ
for(Account acc : accountList){

    // 取引先責任者でループ
    for(Contact con : acc.Contacts__r){
    
        // 処理
    }
}

このようにすれば、処理回数は[取引先の数] + [取引先責任者の数]となり、レコードが多い場合は上の例より処理回数が少なくなります。

項目により紐付けが無い場合はMapを使うのが便利です。

分かりやすいように取引先のIdをキーとしています。

List<Account> accountList;
List<Contact> contactList;
Map<String, List<Conrtact>> keyContactMap;

// 取引先を取得する
accountList = [select Id from Account];
// 取引先責任者を取得する
contactList = [select Id, AccountId from Contact];
// keyから取引先責任者を取得するMapを作成する
keyContactMap = new Map<String, List<Contact>>();
for(Contact con : contactList){

    List<Contact> tmpList;

    // キーに対応するリストが無い場合は作成する
    if(!keyContactMap.containsKey(con.AccountId)){
    
        // 取引先のIdをキーとする
        keyContactMap.put(con.AccountId, new List<Contact>());
    }
    
    // Mapからリストを取得する
    tmpList = keyContactMap.get(con.AccountId);
    // リストに取引先責任者を追加する
    tmpList.add(con);
}

// 取引先でループ
for(Account acc : accountList){

    // キーに紐づく取引先責任者でループ
    for(Contact con : keyContactMap.get(acc.Id)){
    
        // 処理
    }
}

この状態であれば、[取引先の数] +( [取引先責任者の数] * 2)となるでしょうか。

最初の状態よりは処理が少なくなると思います。

レコードが多い場合は処理に時間がかかることが多いため、注意が必要ですね。

ちなみに、このように直すのが100%良いというわけではないので悪しからず。

One Response to "【Salesforce】System.LimitException: Apex CPU time limit exceeded"

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です