+ Start a Discussion
Jessica PuckettJessica Puckett 

Apex Trigger & DataLoader: System.LimitException: Apex CPU time limit exceeded

I am attempting to learn Apex and last week successfully deployed my first (and admittedly rudimentary) Apex trigger to production.  Everything was going great until I attempted to update some of my Contact records via DataLoader.  I received a System.LimitException: Apex CPU time limit exceeded error.  I was able to successfully break my .csv file into 200-part pieces and upload, but I know there must be a better way.  As I understand it, the loops in my trigger are the cause, but I'm not sure how to improve the code to solve this.  My code is below and suggestions are greatly appreciated!

trigger contactDupCheck2 on Contact (before insert, before update, before delete) {
    set<string> emailSet = new set<string>();
    List<contact> contactList = new list<contact>();
    
    for(contact c : trigger.new){
        if(c.email!=null || c.email!=''){
            emailSet.add(c.email);
            contactList.add(c);
        }
    }
    List<Contact> listExistingContact = [select Id, email, LastName from Contact where email in: emailSet and id not in : trigger.new];
    for(contact currCon: contactList ){
    currcon.duplicate_email__c=false;
        for(contact exiscon : listExistingContact ){
            if(currcon.email==exiscon.email){
                currcon.duplicate_email__c=true;
            } else {
            currcon.duplicate_email__c=false;
            }
            if(currcon.email==null || currcon.email==''){
            currcon.duplicate_email__c=false;
            }
           
        }
    }
}
Best Answer chosen by Jessica Puckett
Abhishek M.Abhishek M.
Hi Jessica,
CPU Time limit mainly ocurs due to excexx processing time.
For this we need to avoid nested for loops, minimize If conditions, use SOQL For loops, etc.

I have somewhat updated your above code to minimize the CPU processing time as follows,

trigger contactDupCheck2 on Contact (before insert, before update, before delete) {
    set<string> emailSet = new set<string>();
    List<contact> contactList = new list<contact>();
    
    for(contact c : trigger.new){
        if(c.email!=null || c.email!=''){
            emailSet.add(c.email);
            contactList.add(c);
        }
    }
    
    List<Contact> listExistingContact = [select Id, email, LastName from Contact where email in: emailSet and id not in : trigger.new];
    Map<String, Contact> emailVsContactMap = new Map<String, Contact>();

    for(Contact con : listExistingContact){
        if(c.email!=null || c.email!='')
            emailVsContactMap.put(con.Email, con);
    }
    
    for(contact currCon: contactList ){
        currcon.duplicate_email__c = false;
        if(emailVsContactMap.containsKey(currCon.Email))
            currcon.duplicate_email__c=true;
    }
}
OR
trigger contactDupCheck2 on Contact (before insert, before update, before delete) {
    set<string> emailSet = new set<string>();
    List<contact> contactList = new list<contact>();
    
    for(contact c : trigger.new){
        if(c.email!=null || c.email!=''){
            emailSet.add(c.email);
            contactList.add(c);
        }
    }
    List<Contact> listExistingContact = [select Id, email, LastName from Contact where email in: emailSet and id not in : trigger.new];
    for(contact currCon: contactList ){
        currcon.duplicate_email__c = false;
        for(contact exiscon : listExistingContact ){
            if(currcon.email == exiscon.email)
                currcon.duplicate_email__c=true;
        }
    }
}
========================================================================================================
Note: Just keep in mind, avoid writting the whole logic in Trigger, create an handler class, write your logic their and call that class from the trigger.
Reason being, this makes your code reusable and testable.

- Hope this helps

All Answers

Abhishek M.Abhishek M.
Hi Jessica,
CPU Time limit mainly ocurs due to excexx processing time.
For this we need to avoid nested for loops, minimize If conditions, use SOQL For loops, etc.

I have somewhat updated your above code to minimize the CPU processing time as follows,

trigger contactDupCheck2 on Contact (before insert, before update, before delete) {
    set<string> emailSet = new set<string>();
    List<contact> contactList = new list<contact>();
    
    for(contact c : trigger.new){
        if(c.email!=null || c.email!=''){
            emailSet.add(c.email);
            contactList.add(c);
        }
    }
    
    List<Contact> listExistingContact = [select Id, email, LastName from Contact where email in: emailSet and id not in : trigger.new];
    Map<String, Contact> emailVsContactMap = new Map<String, Contact>();

    for(Contact con : listExistingContact){
        if(c.email!=null || c.email!='')
            emailVsContactMap.put(con.Email, con);
    }
    
    for(contact currCon: contactList ){
        currcon.duplicate_email__c = false;
        if(emailVsContactMap.containsKey(currCon.Email))
            currcon.duplicate_email__c=true;
    }
}
OR
trigger contactDupCheck2 on Contact (before insert, before update, before delete) {
    set<string> emailSet = new set<string>();
    List<contact> contactList = new list<contact>();
    
    for(contact c : trigger.new){
        if(c.email!=null || c.email!=''){
            emailSet.add(c.email);
            contactList.add(c);
        }
    }
    List<Contact> listExistingContact = [select Id, email, LastName from Contact where email in: emailSet and id not in : trigger.new];
    for(contact currCon: contactList ){
        currcon.duplicate_email__c = false;
        for(contact exiscon : listExistingContact ){
            if(currcon.email == exiscon.email)
                currcon.duplicate_email__c=true;
        }
    }
}
========================================================================================================
Note: Just keep in mind, avoid writting the whole logic in Trigger, create an handler class, write your logic their and call that class from the trigger.
Reason being, this makes your code reusable and testable.

- Hope this helps
This was selected as the best answer
rajat Maheshwari 6rajat Maheshwari 6

Hi Jessica,

Hope it will helps :) Please let me know, in case of issue 

trigger contactDupCheck2 on Contact (before insert, before update, before delete) {
    set<string> emailSet = new set<string>();
    List<contact> contactList = new list<contact>();
    
    for(contact c : trigger.new){
        if(c.email!=null || c.email!=''){
            emailSet.add(c.email);
            contactList.add(c);
        }
    }
	
	Map<String,Integer> mp_Aggregate = new Map<String,Integer>();
	
	for(AggregateResult aggResult : [select Id, email, Count(Id) from Contact where email in: emailSet and id not in : trigger.newMap.keyset() group by email,id])
	
	   {
	      mp_Aggregate.put((String)aggResult.get('email'), (Integer)aggResult.get('expr0'));
	   }
	   
	   for(contact c : trigger.new)
	     {
		   if(mp_Aggregate!=null && mp_Aggregate.containsKey(c.email))
		       {
			     c.duplicate_email__c = true;
		       }
			   
		    else 
			  c.duplicate_email__c = false;
	
   
          }
}

Thanks
Rajat Maheshwari
rajatzmaheshwari@gmail.com
Jessica PuckettJessica Puckett
Thank you both for your help and guidance!