Flow Get Records Benchmarking

Welcome back for another Flow benchmarking post. This time the relative performance of querying every field in a 100 field, 300 field, and 500 field custom object using a “Get Records” in a flow is done.

# of ColumnsNo Automation Average10 of N Fields Selected AverageAll Fields Selected Average
100247.1 ms661.8 ms2592.7 ms
300657.5 ms1265.0 ms6867.8 ms
5001074.3 ms1830.5 ms11,364.8 ms

Let me start off with saying that these numbers shouldn’t be taken to mean that N columns being queried take X time. It’s more like X query time plus Y overhead. Also, the “All Fields Selected” used an invocable apex action to force the Flow to query all fields and that’s an extra step compared with the “10 of N fields” which doesn’t use the apex invocable action.

Observations

  • Inserting 200 records with all 500 custom text(255) fields took longer than expected. I thought maybe 500 milliseconds but took just over a second on average.
  • As the number of columns increase, the performance in each case is increasing linearly. I thought it would’ve increased faster but glad it doesn’t.
  • Selecting all the fields takes a lot more time than just the manually selected ones, especially when invoking Apex that does nothing.

Get Records Guidelines

  • Use “Automatically store all fields” as the default option but only if it doesn’t get passed into a sub-flow or apex action which causes it to have all fields queried.
  • Don’t pass records from “Get Records” to sub-flows or apex actions. Pass record ids instead so that the sub-flows and apex actions can query the information needed. This leads to better reuse because it has a very loose dependency on the calling flow. If the calling flow has to know which fields the sub-flow or apex action needs, it makes maintenance harder since if the sub-flow or apex action needs more fields, everything that uses it know has to query the additional fields.

Methodology

A custom object was created for each scenario. 9 in total. Each object was created with N custom text(255) fields. Execute anonymous code was used to insert 200 records with every custom text field filled with text. Limits.getCPUTime was executed before and after the insert statement and then used to calculate the total insertion time. 10 run records were then inserted in the “Benchmark Results” object.

The “No Automation” objects contains no automation whatsoever. It was used to establish a baseline for inserting 200 records with more and more fields as the objects got larger.

10 of N Fields Selected. 10 fields from Objects with 100, 300, and 500 fields were queried using a “Get Records” where 10 text fields were manually selected to be queried. This was done in an after-insert flow where the inserted record was queried by its Id in the “Get Records”.

All Fields Selected. All fields from Objects with 100, 300, and 500 fields were queried using a “Get Records”. That was done by using the “Automatically store all fields” and passing that variable to an Apex Invocable action whose input were those records. The Apex Invocable Action doesn’t do anything and is used solely for causing all the object’s fields to be queried. This was done in an after-insert flow where the inserted record was queried by its Id in the “Get Records”.

100 Fields

Baseline No Automation Performance

Run #Time (Milliseconds)
1218
2252
3261
4217
5211
6283
7261
8265
9268
10235

Average: 247.1 milliseconds

Select 10 of 100 Fields Performance

Run #Time (Milliseconds)
1716
2659
3693
4597
5649
6769
7591
8579
9577
10788

Average: 661.8 milliseconds

All 100 Fields Performance

Run #Time (Milliseconds)
12201
22400
32523
42671
52575
62634
72218
83118
93148
102439

Average: 2592.7 milliseconds

300 Fields

Baseline No Automation Performance

Run #Time (Milliseconds)
1620
2706
3597
4581
5716
6613
7678
8582
9786
10696

Average: 657.5 milliseconds

Select 10 of 300 Fields Performance

Run #Time (Milliseconds)
11384
21225
31272
41254
51223
61156
71246
81301
91147
101442

Average: 1265 milliseconds

All 300 Fields Performance

Run #Time (Milliseconds)
17606
26619
36596
46600
57266
67071
76713
86807
96843
106557

Average: 6867.8 milliseconds

500 Fields

Baseline No Automation Performance

Run #Time (Milliseconds)
11057
2980
3945
41247
51079
61137
71065
8989
91029
101215

Average: 1074.3 milliseconds

Select 10 of 500 Fields Performance

Run #Time (Milliseconds)
11740
21986
31752
41641
51631
62028
72044
81700
91824
101959

Average: 1830.5 milliseconds

All 500 Fields Performance

Run #Time (Milliseconds)
110,930
212,133
310,535
412,114
510,790
611,087
712,167
811,326
910,776
1011,790

Average: 11,364.8 milliseconds

Next Steps / Further Research

  • Update the Benchmarking Package to include this work.
  • Benchmark overhead simply invoking Apex from a flow. I wonder how much of the Select All performance is attributable to the apex invocation.
  • Do the Select All by manually selecting all the fields. I’m not doing that by point-n-click. I suspect I’ll have to download the flow metadata using a tool, update the raw metadata using some code to specify all the fields to query, and then save it back to the org.

What are thoughts??

5 thoughts on “Flow Get Records Benchmarking”

  1. Luke, this is great research, and I’m glad that Adam White posted a link to this from UnofficialSF.com.

    I’d like to encourage you to take this one step farther. What conclusions do you draw from this data? Do you have any recommendations as a result of it?

    1. Alex,

      Thanks for the feedback.

      My recommendations were put in the guidelines section. In short, use the “Automatically store all fields” option by default. Also, don’t use “Automatically store all fields” to pass to a sub-flow or apex action because it’ll query all fields so pass record ids instead.

      It would be awesome if the Salesforce documentation was updated to explain how the option worked in more detail.

  2. I don’t understand the recommendation to “Automatically store all fields” by default and why it’s not to select the fields you need instead. The #’s in the tests here seem to support only selecting the fields needed throughout the whole process first time vs all. From what I understand the flow view state is also affected when we select more fields which can lead to the “Interview too large to save” message.

    1. I think you also got tripped up by the “Automatically store all fields” setting’s name. “Automatically store all fields” only queries the fields used in the flow and not every field on the Object. From what I’ve seen, the only exception is that every field will be queried if the Get Record’s record(s) are passed to a sub-flow or an Apex Action as input. That’s how I was able to test querying these very large custom objects in this post.

      Based on that, “Automatically store all fields” should be the default since the engine will query the fields it needs and reduces build time / maintenance for the flow builder AND one should only pass record ids to a sub-flow or apex action. The sub-flows or apex actions should query the fields they need and not require the caller to know which fields to pass to it.

      Hopefully that clears it up.

Comments are closed.