10

I have a twist on this question. What is the relative performance of each of the following methods?

Via Peter Knolle:

public static Set<String> deserializeToStrings(Set<Id> input)
{
    return (Set<String>)JSON.deserialize(JSON.serialize(input), Set<String>.class);
}

Via Jenny B (and sfdcfox):

public static Set<String> stringify(Set<Id> input)
{
    return new Set<String>(String.join(new List<id>(input), ',').split(','));
}

Via E.J. Wilburn:

public static Set<String> castToStrings(Set<Id> input)
{
    return new Set<String>((List<String>)new List<Id>(input));
}

I have been using the third methodology and I am curious if it is more or less efficient than the others.

3
  • Adrian -- option 2 fails when the input is an empty list; the resulting set<String> has one element with value equal to empty string because split() on an empty list results in a list of size 1 with member[0] value = empty string. Option 2 has to be written more 'cleverly'
    – cropredy
    Commented Mar 7, 2016 at 0:39
  • @crop1645 I think they're all missing null checks too. I just wanted to analyze what was out there from a performance perspective. Good point though, it can certainly be improved (which would probably slow it down a tad bit more).
    – Adrian Larson
    Commented Mar 7, 2016 at 1:48
  • options 1 and 3 are fine as is on empty set<id> input; only option 2 has the issue
    – cropredy
    Commented Mar 7, 2016 at 2:05

1 Answer 1

11

Approach

This should be my final update. I reran my tests, setting all Debug Levels to NONE except Apex, which I set to ERROR. The findings are more or less unchanged: casting beats all other approaches. I added more data, however, to demonstrate the level of difference more rigorously.

I used the following strategy to profile the above in Execute Anonymous:

static Set<Id> generateDummyIds(Integer size)
{
    Set<Id> ids = new Set<Id>();
    for (Integer i=0; i<size; i++)
    {
        String suffix = String.valueOf(i).leftPad(15).replace(' ', '0');
        ids.add(Id.valueOf('001' + suffix));
    }
    return ids;
}
final Integer SET_ELEMENTS = 0;
final Integer ITERATIONS = 1000;

Set<Id> input = generateDummyIds(SET_ELEMENTS);
Long start = Datetime.now().getTime();
for (Integer i = 0; i < ITERATIONS; i++) PerformanceTesting.deserializeToStrings(input);
system.debug(LoggingLevel.ERROR, Datetime.now().getTime() - start);

I used the following value combinations ten times each:

  • SET_ELEMENTS = 0 with ITERATIONS = 1000 for 10k sample size
  • SET_ELEMENTS = 1 with ITERATIONS = 1000 for 10k sample size
  • SET_ELEMENTS = 1000 with ITERATIONS = 50 for 500 sample size
  • SET_ELEMENTS = 100000 with ITERATIONS = 1 for 10 sample size

Modifications

I added a fourth method out of curiosity, even though OP of that question requested to avoid it. This method provides a baseline against which to measure alternatives.

public static Set<String> loopToStrings(Set<Id> input)
{
    Set<String> output = new Set<String>();
    for (Id id : input) output.add(id);
    return output;
}

I also modified the stringify method to produce the correct results as noted by @crop1645:

public static Set<String> stringify(Set<Id> input)
{
    return (input == null || input.isEmpty()) ? new Set<String>() :
        new Set<String>(String.join(new List<id>(input), ',').split(','));
}

Data

Of note is that the deserializeToStrings and stringify methods both failed with 100k elements in the set. The former failed due to heap size exceeded, the latter got a REGEX_TOO_COMPLICATED error.

First let's take a look at milliseconds per call:

                  0       1      1k         100k
deserialize  0.2498  0.2118  14.290   HEAP ERROR
stringify    0.0657  0.1023   2.276  REGEX ERROR
loop         0.0465  0.0914  17.164       1705.4
cast         0.0385  0.0594   2.000        210.0

Chart - Milliseconds Per Call

Next let's examine calls per second:

                 0        1     1k           100k
deserialize   4003     4272     70     HEAP ERROR
stringify    15221     9775    439    REGEX ERROR
loop         21505    10941     58           0.59
cast         25974    16835    500           4.76

Chart - Calls Per Second

3
  • 6
    So, I'd go with the direct cast-to-strings, then. I learned something new today.
    – sfdcfox
    Commented Mar 6, 2016 at 18:15
  • In fact, it is the only approach that significantly beats out looping.
    – Adrian Larson
    Commented Mar 6, 2016 at 18:29
  • there have been a rash of these 'which is better' posts recently - perhaps you could collect them all into a consolidated blog post that is SEO; as noted in my comment to the OP, option 2 needs enhancement
    – cropredy
    Commented Mar 7, 2016 at 0:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .