You need to sign in to do that
Don't have an account?
ChickenOrBeef
Nearing SOQL governor limits, Need advice
Hey everyone,
When creating an opportunity, I'm getting those "Apex governor limit warning" emails telling me that 89 SOQL queries were ran (out of the limit of 100).
For my triggers, I create one main trigger for each object which calls a bunch of classes. So the SOQL queries are made in each class. Here is my opportunity trigger:
The individual classes don't have too many unneeded SOQL queries, so I'm guessing the only way to improve this situation is to make large queries in the main trigger itself, pass those lists into the classes, and then iterate on them? Does that sound right?
Thanks!
-Greg
When creating an opportunity, I'm getting those "Apex governor limit warning" emails telling me that 89 SOQL queries were ran (out of the limit of 100).
For my triggers, I create one main trigger for each object which calls a bunch of classes. So the SOQL queries are made in each class. Here is my opportunity trigger:
trigger MainTriggerOpportunity on Opportunity (before insert, before update, after insert, after update) { if(trigger.isBefore){ if(trigger.isInsert){ if(checkRecursive.runBeforeInsertOnce()){ ClassOppIndustry updater = new ClassOppIndustry(); updater.updateOppIndustry(Trigger.new); ClassRenewalDate updater1 = new ClassRenewalDate(); updater1.updateRenewalDate(Trigger.new); ClassLeadConvertUpdates updater2 = new ClassLeadConvertUpdates(); updater2.updateLeadConvertFields(Trigger.new); ClassStageDateStampInsert updater3 = new ClassStageDateStampInsert(); updater3.stampDate(Trigger.new); } } if(trigger.isUpdate){ if(checkRecursive.runBeforeUpdateOnce()){ ClassOppIndustry updater = new ClassOppIndustry(); updater.updateOppIndustry(Trigger.new); ClassRenewalDate updater1 = new ClassRenewalDate(); updater1.updateRenewalDate(Trigger.new); ClassBrandParent updater2 = new ClassBrandParent(); updater2.addBrandParent(Trigger.new); ClassCallScheduledAdvance updater3 = new ClassCallScheduledAdvance(); updater3.addCallScheduledDate(Trigger.new,Trigger.oldMap); ClassStageDateStamp updater4 = new ClassStageDateStamp(); updater4.stampDate(Trigger.new,Trigger.oldMap); } } } if(trigger.isAfter){ if(trigger.isInsert){ if(checkRecursive.runAfterInsertOnce()){ ClassRenewalProcess updater = new ClassRenewalProcess(); updater.updateRenewalStatus(Trigger.new); ClassOppBrandCreate updater1 = new ClassOppBrandCreate(); updater1.addBrand(Trigger.new); ClassOppTeamMember updater2 = new ClassOppTeamMember(); updater2.insertOpp(Trigger.new); ClassPrimaryContactCopy updater4 = new ClassPrimaryContactCopy(); updater4.copyPrimary(Trigger.new); ClassOppPicklists updater5 = new ClassOppPicklists(); updater5.updatePicklists(Trigger.new); ClassBDSourceCreate updater6 = new ClassBDSourceCreate(); updater6.addBDSource(Trigger.new); ClassMapPlatform updater7 = new ClassMapPlatform(); updater7.copyPlatform(Trigger.new); ClassAnnualDealRevenue updater8 = new ClassAnnualDealRevenue(); updater8.addAnnualRevenue(Trigger.new); ClassDemandGenOpportunity updater9 = new ClassDemandGenOpportunity(); updater9.addContactRoles(Trigger.new); } } if(trigger.isUpdate){ if(checkRecursive.runAfterUpdateOnce()){ ClassRenewalProcess updater = new ClassRenewalProcess(); updater.updateRenewalStatus(Trigger.new); ClassOppBrandCreate updater1 = new ClassOppBrandCreate(); updater1.addBrand(Trigger.new); ClassDrawLoopUpdates updater3 = new ClassDrawLoopUpdates(); updater3.updateDrawLoopFields(Trigger.new); ClassPrimaryContactCopy updater4 = new ClassPrimaryContactCopy(); updater4.copyPrimary(Trigger.new); ClassOppPicklists updater5 = new ClassOppPicklists(); updater5.updatePicklists(Trigger.new); ClassBDSourceCreate updater6 = new ClassBDSourceCreate(); updater6.addBDSource(Trigger.new); ClassMapPlatform updater7 = new ClassMapPlatform(); updater7.copyPlatform(Trigger.new); ClassAnnualDealRevenue updater8 = new ClassAnnualDealRevenue(); updater8.addAnnualRevenue(Trigger.new); } } } }
The individual classes don't have too many unneeded SOQL queries, so I'm guessing the only way to improve this situation is to make large queries in the main trigger itself, pass those lists into the classes, and then iterate on them? Does that sound right?
Thanks!
-Greg
You could substitute Accounts for whatever it is you are querying and there might be more than one object being queried, BUT, if those three classes each queried the Account table, here you would only query it once then use that for each of the methods.
All Answers
I think that's the first step for me, since while my Opportunity trigger only has 49 total SOQL queries, my Opportunity, Account, and Contact triggers have 112 SOQL queries combined. So I'm guessing all three triggers are being run, but I'd like to see specifically which queries are running.
Then I can try and put some queries within IF statements, combine some queries, and perhaps make a larger query in the main trigger which passes the list into multiple classes.
Thanks!
-Greg
I just played around with the filter and I pretty much found what I'm looking for when I filtered the logs by "SOQL_EXECUTE_BEGIN". The only issue is that I can't see which Class or Method those queries are in. So I tried filtering the logs by "METHOD_ENTRY", but that also incudes the "SYSTEM_METHOD_ENTRY" events, which clogs up the log. Any ideas?
Thanks!
-Greg
You can try opening up the Developer Console - while it's open, it will create a log for each trasnaction and then you can filter those logs more easily with the filter tools they provide. The other thing you can do is download the log and open it up in a text editor and get rid of the all of the debug statements you don't need.
Otherwise, look for the SOQL_EXECUTE_BEGIN, the look up to the last open METHOD_ENTRY and that should tell you from which method the SOQL query is being run.
Looking at your trigger, it's good that you are putting all the business logic in a class, but you might want to consider creating a class that handles all of that traffic and only calls the methods necessary. I'm guessing that many of those classes is executing SOQL that is nearly redundant. Perhaps you could create a method that makes one query and then in a for loop you populate lists or maps for each of those methods. Then you can check to see if the list or map is populated, and if it is, call the method and pass it the appropriate data structure.
As for your last paragraph, are you saying I should make the queries in the main trigger, divy up the records into lists and maps (in the trigger), check to see if the lists and maps are populated (in the trigger), and then pass those lists and maps into the called classes?
You could substitute Accounts for whatever it is you are querying and there might be more than one object being queried, BUT, if those three classes each queried the Account table, here you would only query it once then use that for each of the methods.