Notes
Governor limits are an important aspect of Salesforce development that every developer should be familiar with. These limits ensure that the Salesforce platform remains stable and scalable, even when dealing with large amounts of data and complex workflows. In this article, we'll take a closer look at what governor limits are, how they work, and why they're important.
What are governor limits? Governor limits are enforced by Salesforce to ensure that developers don't misuse the platform's resources. These limits are designed to prevent a single user or organization from monopolizing system resources, which could cause performance issues or even system downtime. There are limits on the amount of data that can be queried, the number of records that can be processed, and the amount of time that can be spent executing code.
How do governor limits work? Governor limits are implemented in various ways, depending on the type of operation being performed. For example, there are limits on the number of SOQL queries that can be performed per transaction, the number of DML operations that can be performed per transaction, and the amount of heap size that can be used by Apex code. When a limit is exceeded, an exception is thrown, and the transaction is rolled back.
Why are governor limits important? Governor limits are important because they help ensure the stability and scalability of the Salesforce platform. Without these limits, a single user or organization could monopolize system resources, causing performance issues or even system downtime. By enforcing these limits, Salesforce can ensure that the platform remains stable and available to all users.
Tips for working with governor limits Here are some tips for working with governor limits:
- Always test your code in a development environment before deploying to production.
- Keep your code as efficient as possible to minimize resource usage.
- Use bulk processing techniques to process large amounts of data in batches.
- Monitor your code's resource usage to identify areas where improvements can be made.
- Avoid running code synchronously whenever possible to minimize the impact on system performance.
SOQL Query Limit
List<Contact> contacts = [SELECT Id, Name FROM Contact];
for (Contact c : contacts) {
List<Opportunity> opps = [SELECT Id FROM Opportunity WHERE ContactId = :c.Id];
}
This code queries for all Contacts and then performs a separate SOQL query for Opportunities related to each Contact. If there are more than 100 Contacts, this code will exceed the SOQL query limit and throw an exception.
To avoid this, the code can be modified to perform a single query for all Opportunities:
List<Contact> contacts = [SELECT Id, Name, (SELECT Id FROM Opportunities) FROM Contact];
for (Contact c : contacts) {
List<Opportunity> opps = c.Opportunities;
}
CPU Time Limit
The amount of CPU time that can be used by Apex code in a single transaction is limited to 10,000 milliseconds. Here's an example of code that exceeds this limit:
The number of SOQL queries that can be performed in a single transaction is limited to 100. Here's an example of code that exceeds this limit:
List<Account> accounts = [SELECT Id FROM Account];
for (Account a : accounts) {
for (Contact c : [SELECT Id FROM Contact WHERE AccountId = :a.Id]) {
c.LastName = 'Test';
update c;
}
}
This code updates the LastName field of all Contacts related to each Account. If there are many Contacts, this code will exceed the CPU time limit and throw an exception.
To avoid this, the code can be modified to use bulk processing:
List<Account> accounts = [SELECT Id FROM Account];
List<Contact> contactsToUpdate = new List<Contact>();
for (Account a : accounts) {
for (Contact c : [SELECT Id, LastName FROM Contact WHERE AccountId = :a.Id]) {
c.LastName = 'Test';
contactsToUpdate.add(c);
}
}
update contactsToUpdate;
This code performs a single update for all Contacts, reducing the amount of CPU time used.
Heap Size Limit
The amount of heap size that can be used by Apex code in a single transaction is limited to 6 MB. Here's an example of code that exceeds this limit:
List<String> longStrings = new List<String>();
for (Integer i = 0; i < 100000; i++) {
longStrings.add('a');
}
String concatenatedString = '';
for (String s : longStrings) {
concatenatedString += s;
}
This code creates a large list of strings and then concatenates them into a single string. If there are too many strings, this code will exceed the heap size limit and throw an exception.
To avoid this, the code can be modified to use a StringBuilder:
List<String> longStrings = new List<String>();
for (Integer i = 0; i < 100000; i++) {
longStrings.add('a');
}
StringBuilder sb = new StringBuilder();
for (String s : longStrings) {
sb.append(s);
}
String concatenatedString = sb.toString();
DML Rows Limit The number of records that can be processed in a single DML statement is limited to 10,000. Here's an example of code that exceeds this limit:
List<Account> accountsToUpdate = new List<Account>();
for (Integer i = 0; i < 20000; i++) {
Account a = new Account();
a.Name = 'Test ' + i;
accountsToUpdate.add(a);
}
update accountsToUpdate;
This code creates 20,000 new Account records and then tries to update them in a single DML statement. If there are too many records, this code will exceed the DML rows limit and throw an exception.
To avoid this, the code can be modified to use batch processing:
List<Account> accountsToUpdate = new List<Account>();
for (Integer i = 0; i < 20000; i++) {
Account a = new Account();
a.Name = 'Test ' + i;
accountsToUpdate.add(a);
}
Database.SaveResult[] results = Database.insert(accountsToUpdate, false);
for (Database.SaveResult result : results) {
if (!result.isSuccess()) {
// handle error
}
}
DML Statements Limit The number of DML statements that can be performed in a single transaction is limited to 150. Here's an example of code that exceeds this limit:
List<Account> accountsToInsert = new List<Account>();
List<Account> accountsToUpdate = new List<Account>();
List<Account> accountsToDelete = new List<Account>();
for (Integer i = 0; i < 50; i++) {
Account a = new Account();
a.Name = 'Test ' + i;
accountsToInsert.add(a);
}
for (Integer i = 0; i < 50; i++) {
Account a = [SELECT Id, Name FROM Account WHERE Name = 'Test ' + i];
a.Name = 'Test Updated ' + i;
accountsToUpdate.add(a);
}
for (Integer i = 0; i < 50; i++) {
Account a = [SELECT Id, Name FROM Account WHERE Name = 'Test Updated ' + i];
accountsToDelete.add(a);
}
insert accountsToInsert;
update accountsToUpdate;
delete accountsToDelete;
This code performs 150 DML statements: 151 inserts. If there are too many records, this code will exceed the DML statements limit and throw an exception.
To avoid this, the code can be modified to use bulk processing:
for (Integer i = 0; i <= 150; i++) {
Account ac = new Account();
ac.Name = 'Test ' + i;
insert ac;
}
To avoid this:
List<Account> acList= new List<Account>();
for (Integer i = 0; i <= 150; i++) {
Account ac = new Account();
ac.Name = 'Test ' + i;
acList.add(ac);
}
insert acList;
In conclusion, governor limits are an important aspect of Salesforce development that every developer should be familiar with. These limits help ensure the stability and scalability of the Salesforce platform, and they can be enforced in various ways depending on the type of operation being performed. By following best practices and keeping these limits in mind, developers can create efficient and effective code that maximizes the platform's potential.