Performance Profiling & Debug Logs

0/2 in this phase0/41 across the roadmap

📖 Concept

Performance profiling is how you identify bottlenecks, optimize slow queries, and ensure your Salesforce solution scales. Understanding debug logs, the Developer Console, and profiling tools is essential.

Debug Logs — your primary profiling tool:

Log Categories:
  Database   — SOQL queries, DML operations  
  Workflow   — Flow/PB/Workflow rule execution
  Validation — Validation rule evaluation
  Callout    — HTTP callout details
  Apex_Code  — Apex execution, variable values
  System     — System-level operations
  
Log Levels:
  NONE → ERROR → WARN → INFO → DEBUG → FINE → FINER → FINEST

The Query Plan Tool: Available in the Developer Console (Query Editor → Query Plan), it shows:

  • Whether your query is selective
  • Which index (if any) will be used
  • Estimated number of rows
  • Cost comparison of different query plans

Performance Anti-Patterns:

  1. Non-selective queries on LDV objects — Full table scans
  2. SOQL in loops — N queries instead of 1
  3. Trigger recursion — Same trigger firing multiple times
  4. Formula field chains — Complex formulas on related objects
  5. Roll-up summary on LDV — Recalculating across millions of records
  6. Complex sharing rules — Excessive sharing recalculation

Salesforce Optimizer: A free tool that analyzes your org and provides recommendations:

  • Unused custom fields, objects, and automations
  • Complex business processes
  • Data model issues
  • Performance bottlenecks

💻 Code Example

codeTap to expand ⛶
1// Performance Profiling Techniques
2
3public class PerformanceProfiling {
4
5 // 1. Custom timer for profiling
6 public class Timer {
7 private Long startTime;
8 private String label;
9
10 public Timer(String label) {
11 this.label = label;
12 this.startTime = System.currentTimeMillis();
13 }
14
15 public Long stop() {
16 Long elapsed = System.currentTimeMillis() - this.startTime;
17 System.debug(LoggingLevel.INFO,
18 '[PERF] ' + label + ': ' + elapsed + 'ms');
19 return elapsed;
20 }
21 }
22
23 // 2. Method profiling wrapper
24 public static void profileMethod() {
25 Timer overallTimer = new Timer('overallProcess');
26
27 // Profile query
28 Timer queryTimer = new Timer('accountQuery');
29 List<Account> accounts = [
30 SELECT Id, Name, Industry,
31 (SELECT Id, LastName FROM Contacts)
32 FROM Account
33 WHERE Industry = 'Technology'
34 LIMIT 1000
35 ];
36 queryTimer.stop();
37
38 // Profile processing
39 Timer processTimer = new Timer('dataProcessing');
40 Map<String, Integer> contactCounts = new Map<String, Integer>();
41 for (Account acc : accounts) {
42 contactCounts.put(acc.Name, acc.Contacts.size());
43 }
44 processTimer.stop();
45
46 // Profile DML
47 Timer dmlTimer = new Timer('dmlUpdate');
48 List<Account> toUpdate = new List<Account>();
49 for (Account acc : accounts) {
50 acc.Description = 'Contacts: ' + acc.Contacts.size();
51 toUpdate.add(acc);
52 }
53 update toUpdate;
54 dmlTimer.stop();
55
56 // Overall
57 Long total = overallTimer.stop();
58
59 // Log limit consumption
60 System.debug(LoggingLevel.INFO, '[PERF] Limits consumed:');
61 System.debug(LoggingLevel.INFO,
62 ' SOQL: ' + Limits.getQueries() + '/' + Limits.getLimitQueries());
63 System.debug(LoggingLevel.INFO,
64 ' DML: ' + Limits.getDmlStatements() + '/' + Limits.getLimitDmlStatements());
65 System.debug(LoggingLevel.INFO,
66 ' CPU: ' + Limits.getCpuTime() + 'ms/' + Limits.getLimitCpuTime() + 'ms');
67 System.debug(LoggingLevel.INFO,
68 ' Heap: ' + Limits.getHeapSize() + '/' + Limits.getLimitHeapSize());
69 }
70
71 // 3. Query optimization analysis
72 public static void analyzeQueryPerformance() {
73 // Selective query — uses index
74 Timer t1 = new Timer('Selective (Name index)');
75 List<Account> r1 = [
76 SELECT Id FROM Account WHERE Name = 'Acme' LIMIT 1
77 ];
78 t1.stop();
79
80 // Non-selective query — full scan
81 Timer t2 = new Timer('Non-selective (Description)');
82 List<Account> r2 = [
83 SELECT Id FROM Account WHERE Description != null LIMIT 1000
84 ];
85 t2.stop();
86
87 // Optimized with indexed filter + non-indexed filter
88 Timer t3 = new Timer('Optimized (indexed + filter)');
89 List<Account> r3 = [
90 SELECT Id FROM Account
91 WHERE CreatedDate = THIS_YEAR // Indexed — narrows first
92 AND Description != null // Non-indexed — filters second
93 LIMIT 1000
94 ];
95 t3.stop();
96 }
97
98 // 4. Platform Cache for repeat queries
99 // Requires Platform Cache allocation in org
100 public static List<Account> getCachedAccounts(String key) {
101 // Check cache first
102 Cache.OrgPartition orgPart = Cache.Org.getPartition('local.CachePartition');
103
104 List<Account> cached = (List<Account>) orgPart.get(key);
105 if (cached != null) {
106 System.debug('Cache HIT for: ' + key);
107 return cached;
108 }
109
110 System.debug('Cache MISS for: ' + key);
111 List<Account> accounts = [
112 SELECT Id, Name, Industry FROM Account LIMIT 100
113 ];
114
115 // Store in cache (TTL: 3600 seconds = 1 hour)
116 orgPart.put(key, accounts, 3600);
117
118 return accounts;
119 }
120
121 // 5. Debug log configuration (for team setup)
122 // Setup → Debug Logs → New → Select User → Set levels:
123 // Database: FINE (see all SOQL)
124 // Apex_Code: DEBUG (see execution flow)
125 // Workflow: INFO (see automation)
126 // System: WARN (reduce noise)
127 // Validation: INFO
128
129 // 6. Analyzing debug log output
130 // Look for patterns:
131 // SOQL_EXECUTE_BEGIN — each query with bind values
132 // SOQL_EXECUTE_END — rows returned, time
133 // DML_BEGIN / DML_END — DML operations
134 // CODE_UNIT_STARTED / CODE_UNIT_FINISHED — trigger/class entry/exit
135 // LIMIT_USAGE_FOR_NS — cumulative limit consumption
136}

🏋️ Practice Exercise

Performance Profiling Practice:

  1. Create a Timer utility class and profile the execution time of different operations
  2. Use the Developer Console to analyze debug logs for a complex transaction
  3. Use the Query Plan tool to compare selectivity of 5 different SOQL queries
  4. Set up Platform Cache and measure the performance improvement for repeated queries
  5. Profile a trigger with 200 records and identify the bottleneck (SOQL, CPU, or DML)
  6. Run the Salesforce Optimizer and implement the top 5 recommendations
  7. Create a performance test that measures operation time with 1, 50, 100, and 200 records
  8. Analyze a debug log to trace a trigger cascade (Account → Contact → Task)
  9. Build a custom performance monitoring object that logs transaction metrics
  10. Write a load test using Data Loader to simulate production-scale data volumes

⚠️ Common Mistakes

  • Setting debug log levels too high (FINEST for everything) — this slows performance and makes logs unreadable. Use FINE for Database, DEBUG for Apex, WARN for everything else

  • Profiling in development with small data — performance issues only appear with production-scale data. Always test with realistic volumes

  • Not using the Query Plan tool — guessing at query performance instead of using the tool that tells you exactly what's happening

  • Ignoring the 'CUMULATIVE_LIMIT_USAGE' section in debug logs — this section shows total limit consumption across the entire transaction, including all triggers and automations

  • Optimizing without measuring — always profile first. The actual bottleneck is often not what you expect

💼 Interview Questions

🎤 Mock Interview

Mock interview is powered by AI for Performance Profiling & Debug Logs. Login to unlock this feature.