Free computer code on screen

Batch Apex encountered an error: Exceeded Apex CPU time limit.

In this post, I would share my recent experience in fixing “CPU time limit” error in Batch apex and reason. When I encountered this error, initially thought that it would be easy to fix by following some of basic rules like :

  1. Remove unnecessary code and loops
  2. Efficient use of collections (Set, Hashmap or List)
  3. Avoid using loop within loop
  4. SOQL query should be indexable
  5. Avoid unnecessary re-initialization of variables
  6. Use Aggregated SOQL (as Database operations not counted in this limit, avoid arithmetic operations in Apex)
  7. Check how much time Workflow rules and process builders are taking
  8. Is there any manage package performing heavy operations in transaction

This piece of code was handed over to me from previous team, so I was not fully aware about full functionality and thought to check debug logs. To my surprise, how many times I tried to get a log, every attempt failed. I was thinking that problem could be in execute method however Batch Apex was failing with no debug logs. I tried all my tricks to get debug log with no success.  Batch Apex was using Query locator and it could fetch up to 50 millions of record and therefore overlooked start method.

Below pseudo code will give you some idea about Batch Apex structure and data volume.

global class SampleBatchApex_CPUError implements Database.Batchable<sObject> {
 
    String query = ' SELECT Field1, Field2, (SELECT Name, Identifier__c FROM childObject__r Where type=\'some value\') FROM Contact';
    
    global Database.QueryLocator start(Database.BatchableContext BC) 
        return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, List<Contact> contacts) {
        //Some code about 100 lines
    }
     
    global void finish(Database.BatchableContext BC) {
        //Perform cleaning and start another Batch job
    }  
}

Data volume in full copy sandbox were like

  • Contact – 270k+
  • ChildObject__c – 270k+

The cause of CPU timeout in my scenario was due to a subquery.

I attempted to analyze the SOQL Query Plan and executed the same query separately in the Developer Console and Workbench. Surprisingly, there were no timeouts. Despite this, I decided to experiment by removing the subquery from the start method and re-executing it in the execute method. To my surprise, this resolved the issue. It became apparent that the subquery within the SOQL was causing the CPU time limit error, preventing the execution from even entering the execute method. This led to confusion as there were no debug logs available. Consequently, I ended up spending a considerable amount of time trying to understand why the debug log wasn’t appearing, instead of focusing on the actual issue at hand.

Key takeaways

  1. If we are getting CPU time limit error (in my experience I have seen many), then avoid using sub-query, its costly and time consuming. Damn !!! I need to tell my colleagues of previous projects to check code for subquery, where they are getting CPU error.
  2. If batch apex error says “First error – some error” , that means error is in start method and don’t even try to hunt for execute method debug logs.