Mass createRow performance when creating hundreds of rows

When building mass edit UIs we’ve encountered slow performance of the createRow method when creating hundreds of records. I’ve attached a basic page that performs increasing volumes of mass row creation, the results I get show 2s for 100 rows and 144s for 1000 rows. Putting aside the wisdom of why we want to create 1000 records, even 100 rows takes too long and he results are not as linear as you’d expect:

Created rows: 1 in 0.023s = 0.023s per row
Created rows: 10 in 0.142s = 0.014s per row
Created rows: 100 in 2.257s = 0.02257s per row
Created rows: 200 in 6.898s = 0.03449s per row
Created rows: 500 in 37.399s = 0.074798s per row
Created rows: 1000 in 144.617s = 0.144617s per row

Our use case is a mass edit table that allows users to “preview” and “configure” a large table (100s of rows), perform some calculations and then save that data to Salesforce for output in an Excel document. We experience sluggish performance when we loop through our data and use createRow to build the transformed data. Are we doing something wrong or is there another way to mass create rows on a model to avoid any bottlenecks? We don’t necessarily have to display the mass created rows in a table but we have (reluctantly) started to move some of our code to Apex to get better performance and (to be fair) for other reasons like reducing network roundtrips.

<skuidpage showsidebar="false" showheader="false">
   <models>
      <model id="Contacts" limit="1000" query="false" createrowifnonefound="false" sobject="Contact">
         <fields>
            <field id="Name"/>
            <field id="LastName"/>
         </fields>
         <conditions>
            <condition type="fieldvalue" value="1" enclosevalueinquotes="true" field="Id"/>
         </conditions>
      </model>
   </models>
   <components>
      <pagetitle model="Contacts">
         <maintitle>
            <template>{{Name}}</template>
         </maintitle>
         <subtitle>
            <template>{{Model.label}}</template>
         </subtitle>
         <actions>
            <action type="custom" label="Create Mass Contacts" window="self" snippet="CreateMassContacts"/>
         </actions>
      </pagetitle>
      <skootable showconditions="true" showsavecancel="false" searchmethod="server" searchbox="false" showexportbuttons="false" pagesize="all" createrecords="false" model="Contacts" buttonposition="" mode="readonly" uniqueid="ContactsTable">
         <fields>
            <field id="Name"/>
            <field id="LastName"/>
         </fields>
         <rowactions/>
         <massactions usefirstitemasdefault="true"/>
         <views>
            <view type="standard"/>
         </views>
      </skootable>
   </components>
   <resources>
      <labels/>
      <javascript>
         <jsitem location="inlinesnippet" name="CreateMassContacts" cachelocation="false">var params = arguments[0],
   $ = skuid.$;
var models = skuid.model.map();
var contacts = models.Contacts;
createRows(1);
contacts.cancel();
createRows(10);
contacts.cancel();
createRows(100);
contacts.cancel();
createRows(200);
contacts.cancel();
createRows(500);
contacts.cancel();
createRows(1000);
//contacts.cancel();
function createRows(noOfRows) {
    var start = new Date().getTime();
    for (var i=0; i&amp;lt;noOfRows; i++) {
        var row = contacts.createRow({
            additionalConditions: [
                { field: 'LastName', value: i, operator: '=', nameFieldValue: this.Name }
            ]
        });
    }
    var end = new Date().getTime();
    console.log('Created rows: ' + noOfRows + ' in ' + (end-start)/1000 + 's = ' + ((end-start)/1000)/noOfRows + 's per row');
}</jsitem>
      </javascript>
      <css/>
   </resources>
</skuidpage>

Hi Stephen,

The issue you’re experiencing with the createRow API being slow is that Skuid runs all of its rendering logic after each createRow.  Each time you add a new row to your model, it takes your browser more and more time to render the table.  In essence, when you call createRow 1000 times, your browser is drawing a progressively larger table 1000 times.

In our common use cases such as updateRow, we’ve created a separate API method called updateRows that modifies all the rows and then when it’s done, handles all of Skuid’s rendering logic.

We haven’t seen a use case like this before, so we didn’t think to make the createRows API method.  I’ve added this item as a feature we need to add to our API.  This should make your adding of 1000 rows MUCH faster.

Hi Ben,

Thanks for the explanation, it makes sense and we’d really like to see the new mass createRows feature so our more advanced scenarios will work faster.

In the meantime do you have any suggestions for a workaround we can use until the new method? Is there someway of “disabling” the render logic after each row. I vaguely recall something Zach posted somewhere about “disconnecting” a model from its component and then reattaching it? Perhaps I can redesign the page and models to perform the required mass creates on an isolated model and then directly copy or move the data to the real “display” model?

Just to prove you’re right and one workaround option that might be available in some scenarios is to not have any component bound to the model so no rendering occurs. You do in fact get the expected linear performance:

Created rows: 1 in 0.011s = 0.011s per row Created rows: 10 in 0.043s = 0.0043s per row<br>Created rows: 100 in 0.389s = 0.00389s per row<br>Created rows: 200 in 0.705s = 0.003525s per row<br>Created rows: 500 in 1.731s = 0.00346s per row<br>Created rows: 1000 in 3.58s = 0.00358s per row

Cheers,
Stephen

Is there an update on this? Is createRows() now available? Thanks!

Any updates on this? I have a quote building tool that gets really slow once you get past 20 or so row rows…

Another person who’d like an update here. Is there even any work around?

I’ve found a couple of ways that can help, but not consistently. I was showing a model in a table that was queried when a button was pressed elsewhere. So I put an action on the button that updated a model condition that meant the table would not be rendered, then did the query (also as an action), then the javascript that called createRow based on those results, then updated the condition again afterwards so that the table would show. This works, but unfortunately, sorting by a table column header causes the slow performance again.

It should be feasible in javascript - there’s unregisterEditor and registerEditor but I can’t quite get it working. After querying the data and creating rows, calling registerEditor doesn’t seem to bring the data into the UI. I suspect there may be some sort of refresh call I need to make.

Anyway, any other workarounds people have found? And to Skuid - any update on createRows()?


Sorry guys.  Its a feature enhancement that we have on our list and have pretty well specced out,  but haven’t been able to get completed. 

In lieu of the feature being added, I thought I’d add my workaround in case anybody else reading this in the future could use it.

Currently, we use actions and rendering features to control the display of UI elements that are registered to a model where createRow is being called. Basically - we hide the UI element whilst our snippet runs and then show it again after the snippet has finished.

Our situation: we have a model which is shown in a table of records, and is modified by a snippet using createRow(). We added a render condition on the table that used a checkbox on a model we weren’t actually modifying. 

Above the table is a button that runs our snippet as an action. We added two extra actions, one at the start and one at the end. All this did was updated the checkbox used to control the rendering of the table.

This approach felt kind of… amateur? Hacky? I did spend time looking at a number of register and unregister methods, as it seems it should be possible to do this from within the snippet - unregister editors against the models, call createRow as many times as needed, then restore the connection to the editor using a register method. However, try as I might, I couldn’t get this to work as I thought it should from the documentation. If anybody better than I is able to achieve it, I’d love to see where I was going wrong!

Your approach garnerned approving smiles from the developers here at Skuid.  Nothing amateurish or hacky about it.  You are using the conditional rendering and action framework tools in a very effective way.  Unexpected?  Maybe.  But effective…

any chance createRows() has made an appearance in Banzai?

Sorry. Not yet… 

+1 from me as well. We are doing a lot of row creation from APIs now and this is very slow

I stumbled upon this older thread. I’ll go ahead and add a +1 from me :smiley:

I know this is a really old post, but it looks like we don’t have a createRows API yet. Is this still a good workaround? I’ve tried unrendering the components while I’m creating rows via the API, but each new row I create is taking longer and longer. 

Are there any new Skuid supported ways to create rows through the API in bulk quickly?

After playing around with it some more I did find another workaround. I was able to base the components on a cloned copy of the model. I then populate the original model via JavaScript. Once I’m done adding rows I get all of the rows and add them to the cloned model via adoptRows().

You guys are awesome!  So I had a mass create that was taking way too long. Now it takes seconds to do all of them.  I simply added a UI only object with a checkbox named “Render”. I set the output table to only render after the UI only checkbox is checked.  Then in the action framework I make my last step after the rows are all created to be to change the field of the UI only checkbox to checked.  Beautifully easy and fast and absolutely no code.

In my experience this sort of methodology only works if the table / UI object hasn’t been rendered yet in the UI at all. If you render it and then hide it and try to rerun the “slow” code, it will again be slow. Even though the object is hidden from rendering, since it was rendered once it still remains in the “items to render” and causes slow updates.

Is there any way to turn off the rendering of an object in SKUID once it has been rendered for the first time, so that we can run these sorts of things without it having to render the row on each create/update?

Mark, see my response to your other post.