19

I was about to reconfigure some of my code to use the newer Schema.describeSObjects(types) method that I had heard was faster than using a globalDescribe.

I made some code to quickly check this and I was dismayed to find that the newer technique is not only not faster, it's about twice as slow as using a global describe. Here's the code I used :

New DescribeSObjects() method

//each block was run separately for timing purposes
String obj = 'Account';
String[] types = new String[]{obj};
System.debug('START DESCRIBE SOBJECTS');

for (Integer i = 0; i < 50; i++) {
  List<Schema.DescribeSobjectResult> results = Schema.describeSObjects(types); 
}
System.debug('FINISH DESCRIBE SOBJECTS');

Old getGlobalDescribe() method

String obj1 = 'Account';
System.debug('START DESCRIBE GLOBAL');

for (Integer i = 0; i < 50; i++) {

  Map<String,Schema.SObjectType> gd = Schema.getGlobalDescribe(); 
  Schema.SObjectType sobjType = gd.get(obj1); 
  Schema.DescribeSObjectResult describeResult = sobjType.getDescribe(); 
}
System.debug('FINISH DESCRIBE GLOBAL');

Over 5 runs of each, the getGlobalDescribe() method took an average of 337ms for 50 describes and the describeSObjects() method took and average of 658ms. This is basically twice as long.

Does anyone have any insight as to why this would be? Any improvements that will significantly improve the accuracy of the resulting data?

As this data stands, I'm sticking with the old method.

One final note: the old technique uses 3 times a much heap (67kb vs 27kb)

29

I suspect, internally, that this code is written in Apex Code and thus suffers the same general performance problems as doing it yourself. If you want a blazing-fast interface, consider using Type instead:

String obj1 = 'Account';
Long time1 = DateTime.now().getTime();

for (Integer i = 0; i < 50; i++) {
    SObjectType r = ((SObject)(Type.forName('Schema.'+obj1).newInstance())).getSObjectType();
    DescribeSObjectResult d = r.getDescribe();
}
Long time2 = DateTime.now().getTime();
System.debug(time2-time1);

This runs in about 10-15ms for 50 describes, while Schema.describeSObjects runs in about 1700-1900ms in my org, and Schema.getGlobalDescribe runs in 300-500ms in my org.

Skipping the global describe shaves off an amazing amount of time. Caching is also acceptable; if you must use Schema.getGlobalDescribe, use it only once to avoid performance issues:

String obj1 = 'Account';
Long time1 = DateTime.now().getTime();

Map<String,Schema.SObjectType> gd = Schema.getGlobalDescribe(); 

for (Integer i = 0; i < 50; i++) {
    Schema.SObjectType sobjType = gd.get(obj1); 
    Schema.DescribeSObjectResult describeResult = sobjType.getDescribe(); 
}
Long time2 = DateTime.now().getTime();
System.debug(time2-time1);

This results in a more respectable time of about 80-140ms instead.

I personally have a static variable that all classes use so I never global describe more than once per transaction:

public static Map<String, SObjectType> globalDescribe {
    get { if(globalDescribe == null) globalDescribe = Schema.getGlobalDescribe();
        return globalDescribe;
    }
}

If it's never used, there's no performance penalty, but when I do need it, I will only need to global describe once.

  • @IllusiveBrian I know it's cached, because it's much faster than it was before, but see my version versus the original version; it's about 200% faster than relying on the internal caching. – sfdcfox May 23 '18 at 1:11
  • Damn, great answer. And using Type.forName('Schema.obj').newInstance() is great. I'll be using this from now on. – Caspar Harmer May 23 '18 at 1:11
0

We have a class configured to determine approval in a Apttus callback. After release we had one case where users reported took 8 hours to do a quote. More typical though it was 2 or 3 minutes. These things are not easy to track down, but we finally found it was the Schema.getGlobalDescribe(). Everytime it was called in a callback it added 10 seconds in delay. That in turn cause the method polling the callback to wait much more than 10 seconds. It would get called multiple times each time we did pricing.

After switching to just do a switch statement base on the class name, the delay was completely gone. Of course that means our metadata configuration we had designed to use and sobject type we specified could only use the few we hard coded in the switch statement. But considering we were only using two different values, it wasn't that much of a tradeoff.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.