[SalesForce] How to solve the System.LimitException: Apex CPU time limit exceeded

I received the following error message during a validation process when I try to deploy my code on my production environment:

System.LimitException: Apex CPU time limit exceeded

Although the reason of this limit exception is due to the nested for loop in my source code I do not see how to modify my code to avoid such exception.

Here is the problematic part of my code with the nested for loop:

private List<LeadConversionContainer> checkByWebsite(Lead leadObj) {
    List<LeadConversionContainer> accountWebsites = new List<LeadConversionContainer>();
    String website = leadObj.Website;
    String leadId = leadObj.Id;
    List<Account> accWebsiteList = [SELECT Website, Url__c, Status__c FROM 
    Account];
    if(website != null && !website.equals('') && accWebsiteList != null) {
        List<String> leadWebsites = extractWebsites(website);
        for (String leadUrl : leadWebsites) {
            String normWebsite = normalizeWebsite(leadUrl);
            String leadWebsite = normWebsite.trim();
            for(Account acc : accWebsiteList) {
                String accountWebsite = acc.Url__c;
                String accountId = acc.Id;
                List<String> extractedAccountWebsite = extractWebsites(accountWebsite);
                for(String accWebsite :extractedAccountWebsite) {
                    String accountSite = normalizeWebsite(accWebsite);
                    if(accountSite != null) {
                        List<String> leadSplitWebsitesList = leadWebsite.split('[,;\\s]');
                        for(String leadSplitUrls :leadSplitWebsitesList) {
                            if(accountSite.equals(leadSplitUrls)) {
                                boolean isAccountStatusActive = isAccountActive(acc);
                                boolean isMerchantApplication = isMerchantApplicationsAttached(acc);
                                if(isAccountStatusActive || isMerchantApplication) {
                                    String reasonToStopConversion = 'Lead Website coincide with Account Website';
                                    LeadConversionContainer leadConvert = new LeadConversionContainer(acc.Id, '', reasonToStopConversion);
                                    accountWebsites.add(leadConvert);
                                }
                            }    
                        }
                    }
                }
            }    
        }
    }
    return accountWebsites;
}

Please advise how to implement and modify my code to avoid such System.LimitException: Apex CPU time limit exceeded exception?

Best Answer

The big issue here isn't nested FOR loops per se; it's that you're querying and then iterating over every Account in your instance for each Lead you process.

This query is non-selective and is likely very slow. You can review the Query Planner in Developer Console for more details.

List<Account> accWebsiteList = [SELECT Website, Url__c, Status__c FROM Account];

But then you're also iterating over the entire Account object in your inner FOR loop:

        for(Account acc : accWebsiteList) {

I would recommend refactoring your code to iterate over the list of Leads you're working with first to accumulate their respective websites, then querying only for Accounts which match those websites using an IN in your WHERE clause. You won't be able to have a method taking a single Lead as a parameter; you'll need to process the list of Leads in batches.

Depending on your data volume and whether the relevant fields are indexed, this might or might not be enough to avoid CPU time errors, but it should certainly improve your performance substantially.

Related Topic