Fixing inefficient Apex: loops, collections and caching
Read an Apex snippet, find the limit it will hit and apply the matching fix: sets and maps instead of queries in loops, map lookups instead of nested loops, values computed once outside the loop, COUNT() instead of loaded rows, static and Platform Cache caching, before-trigger field updates, changed-field guards and one bulk sendEmail call.
Given sample code, identify inefficiencies and demonstrate how to resolve them.
~8 min read · 11 practice questions ·
What the exam expects
- Spot SOQL, DML, describe calls or
sendEmailinside a loop, even hidden in a helper, and rewrite with sets, maps or one bulk call. - Replace nested loops that exhaust CPU time with map lookups.
- Remove work that returns the same value for every record: move it before the loop or use a no-query API such as
UserInfo. - Choose
COUNT(), a static variable or Platform Cache to avoid loading or re-querying data, and use the cache API efficiently. - Cut unnecessary saves with before-trigger field updates and changed-field guards.
Key terms: bulkification (code that handles a whole collection in one pass with constant queries and DML), loop-invariant work (a computation whose result doesn't depend on the loop's record), static variable (a class variable shared for one transaction), Platform Cache (a cache that survives across transactions), changed-field guard (comparing Trigger.new to Trigger.oldMap).
Key facts
- Detail
- 100 synchronous, 200 asynchronous
- Detail
- 50,000 per transaction
- Detail
- 10,000 ms synchronous, 60,000 ms asynchronous
sendEmail calls- Detail
- 10 per transaction
COUNT() row cost- Detail
- One row without
GROUP BY; one per group with it
- Detail
UserInfo.getUserRoleId(), no query
- Detail
- One transaction; reset at the boundary
- Detail
get(key)and test for null, notcontainsthenget
- Detail
- Least recently used keys evicted
Trigger.new changes- Detail
- Saved without DML only in before triggers
Sources for this section (7)
- Execution Governors and Limitsdeveloper.salesforce.com (opens in a new tab)
- Outbound Emaildeveloper.salesforce.com (opens in a new tab)
- Working with SOQL Aggregate Functionsdeveloper.salesforce.com (opens in a new tab)
- UserInfo Classdeveloper.salesforce.com (opens in a new tab)
- Static Variablesdeveloper.salesforce.com (opens in a new tab)
- Platform Cache Best Practicesdeveloper.salesforce.com (opens in a new tab)
- Context Variable Considerationsdeveloper.salesforce.com (opens in a new tab)
- Why does caching each warehouse in a static map inside a single-ID helper still fail for 150 distinct warehouses?
- When does a lazy-loaded static variable re-run its query?
- Why is a before trigger faster than an after trigger for setting a field on the saved records?
- How many query rows does `SELECT COUNT() FROM Case WHERE ...` consume?
- Why should Platform Cache code call `get(key)` and test for null instead of `contains(key)` first?
The questions are free to read. Answers with their sources and self-grading are included with the pack.
Keep reading with the Platform Developer II pack
- Core concepts
- Exam traps
- Worked scenario
The pack includes:
- All 28 lessons of the Platform Developer II guide, with reading progress
- Interactive decision walks and step-by-step sequence steppers
- Inline practice questions and one-click topic practice (11 questions for this lesson)
- An official source cited for every claim
- An AI tutor that answers from the guide
- Unlimited timed practice exams