20 May 2014

That which doesn't limit us makes us stronger

Recently, while writing apex code, I ran up against a number of different limits.

I understand why there needs to be limits with apex. It's a shared development environment and I wouldn't want another organization's code to ever affect my code or organization. That's like protecting me from a neighbor splicing into my cable in order to download movies on my bandwidth.

What helps me manage my limits is when I surface them in the apex code I'm writing.

While playing around with limits, I came up with a quick way to view all of my apex limits and see where I am against those limits.

If you're new to apex limits, try the following:
  1. log into workbench and click on utilities > Apex Execute
  2. copy-paste the following and click Execute:
System.debug('CPU timeout limit: '+Limits.getLimitCPUTime()); 
System.debug('Number of aggregate queries that have been processed with any SOQL query statement: '+Limits.getAggregateQueries()); 
System.debug('Number of aggregate queries that can be processed with SOQL query statements: '+Limits.getLimitAggregateQueries() ); 
System.debug('Number of Web service statements that have been processed: '+Limits.getCallouts()); 
System.debug('total number of Web service statements that can be processed: '+Limits.getLimitCallouts()); 
System.debug('number of child relationship objects that have been returned.: '+Limits.getChildRelationshipsDescribes()); 
System.debug('total number of child relationship objects that can be returned.: '+Limits.getLimitChildRelationshipsDescribes()); 
System.debug('CPU time (in milliseconds) accumulated on the Salesforce servers in the current transaction: '+Limits.getCpuTime() ); 
System.debug('time limit (in milliseconds) of CPU usage in the current transaction.: '+Limits.getLimitCpuTime()); 
System.debug('number of records that have been processed with any statement that counts against DML limits, such as DML statements, the Database.emptyRecycleBin method, and other methods.: '+Limits.getDMLRows()); 
System.debug('total number of records that can be processed with any statement that counts against DML limits, such as DML statements, the database.EmptyRecycleBin method, and other methods.: '+Limits.getLimitDMLRows()); 
System.debug('number of DML statements (such as insert, update or the database.EmptyRecycleBin method) that have been called.: '+Limits.getDMLStatements()); 
System.debug('total number of DML statements or the database.EmptyRecycleBin methods that can be called.: '+Limits.getLimitDMLStatements());System.debug('number of email invocations (such as sendEmail) that have been called.: '+Limits.getEmailInvocations()); 
System.debug('total number of email invocation (such as sendEmail) that can be called.: '+Limits.getLimitEmailInvocations()); 
System.debug('number of field describe calls that have been made: '+Limits.getFieldsDescribes()); 
System.debug('total number of field describe calls that can be made: '+Limits.getLimitFieldsDescribes()); 
System.debug('number of field set describe calls that have been made: '+Limits.getFieldSetsDescribes()); 
System.debug('total number of field set describe calls that can be made: '+Limits.getLimitFieldSetsDescribes()); 
System.debug('number of methods with the future annotation that have been executed (not necessarily completed): '+Limits.getFutureCalls()); 
System.debug('total number of methods with the future annotation that can be executed (not necessarily completed): '+Limits.getLimitFutureCalls()); 
System.debug('approximate amount of memory (in bytes) that has been used for the heap: '+Limits.getHeapSize()); 
System.debug('total amount of memory (in bytes) that can be used for the heap: '+Limits.getLimitHeapSize()); 
System.debug('number of SOQL queries that have been issued: '+Limits.getQueries()); 
System.debug('total number of SOQL queries that can be issued: '+Limits.getLimitQueries()); 
System.debug('number of PicklistEntry objects that have been returned: '+Limits.getPicklistDescribes()); 
System.debug('total number of PicklistEntry objects that can be returned: '+Limits.getLimitPicklistDescribes()); 
System.debug('number of records that have been returned by the Database.getQueryLocator method: '+Limits.getQueryLocatorRows()); 
System.debug('total number of records that have been returned by the Database.getQueryLocator method: '+Limits.getLimitQueryLocatorRows()); 
System.debug('number of records that have been returned by issuing SOQL queries: '+Limits.getQueryRows()); 
System.debug('total number of records that can be returned by issuing SOQL queries: '+Limits.getLimitQueryRows()); 
System.debug('number of RecordTypeInfo objects that have been returned: '+Limits.getRecordTypesDescribes()); 
System.debug('total number of RecordTypeInfo objects that can be returned: '+Limits.getLimitRecordTypesDescribes()); 
System.debug(' number of SOSL queries that have been issued: '+Limits.getSoslQueries()); 
System.debug(' total number of SOSL queries that can be issued: '+Limits.getLimitSoslQueries());
I know that's a lot of system.debug statements, but it turns out there are a lot of limits and a lot of methods to pull out what your limit is versus where you are against your limit.

This is a great way to see all of the various apex limits that are tracked in one place.

Taking this example one step further, I created a new Apex Class called 'LimitsTester' with a single method:

public class LimitsTester{
  public static void tooManyQueries() {
    for (Integer i = 0; i < 200; i++) {
      List<Account> a = [select id from Account Limit 1];
      System.debug('How many queries: '+Limits.getQueries());
      System.debug('Out of how many possible: '+Limits.getLimitQueries());
    }
  }
}
When I execute this apex, it quickly returns an exception that enables me to track when the limit was reached.


All of this is documented but it really helps to surface it early in the development cycle.

1 comment: