CreateMultiple and UpdateMultiple plugins performance
CreateMultiple and UpdateMultiple are currently recommended request types for executing bulk operations on multiple rows of Dataverse tables. They have some limitations described in the product documentation, but according to Microsoft guidelines, they provide the best performance for creating or updating a mass amount of Dataverse records.
One of the newest development features of the Dataverse platform is the possibility of registering plugin execution steps on CreateMultiple and UpdateMultiple requests. You should write plugins for the above-mentioned messages with tables where records may need to be created or updated in bulk or where performance in creating and updating large numbers of rows is important. What is more important in the case of having business logic implemented on the Create or Update request is that the recommendation is to rewrite this code for corresponding Multiple operations handers to provide the best performance of bulk operations on the table records.
In this article, I would like to present the results of some testing scenarios. I’ve tried to compare operations performance when executing bulk data update operations and executing some plugin code on related messages.
Test Scenario
Business logic:
- On the Contact entity we have a “Next Contact Date” attribute (date).
- When contact is created, or “Next Contact Date” is updated – the task of contacting related person is generated.
- Task generation has been implemented as a post-event create/update .NET plugin.
Because of the need for a mass update of contacts with new next contact date values, we need to verify if migrating code into post-event CreateMultiple/UpdateMultiple has an impact on the overall operation performance. The decision about using plugin-based implementation of the above-described business logic has its purpose only in the case of testing handlers of bulk operation performance, which is our true goal. In the real world, this functionality could probably be implemented as an asynchronous operation with no-code development tools.
Test execution prerequisites
Every test is about creating and updating 300 Contact records. All the data rows are created with the “New Contact Date” attribute set up. In the case of updating the “New Contact Date” column, a value has been provided. When the “New Contact Date” value changes, a new Task record in the system is created. This logic is implemented as a synchronous .NET plugin for the related events.
Every test run was executed three times. Test result tables contain the average measured time of operations in seconds.
Test 1
Sequential Create and Update request with plugins steps registered on Create and Update events.
Operation |
Average time (s) |
Create |
48 |
Update |
63 |
Test 2
Using CreateMultiple and UpdateMultiple requests with plugins steps registered on Create and Update events.
Operation |
Average time (s) |
Create |
94 |
Update |
46 |
As you can see, the average measured operation time is longer for record creation and faster in the case of updating records compared to the previous scenario where sequential create and update requests were sent to the Dataverse service.
Test 3
Using CreateMultiple and UpdateMultiple requests with plugins steps registered on CreateMultiple and UpdateMultiple messages
Operation |
Average time (s) |
Create |
16 |
Update |
29 |
In this case – total operation time was much shorter compared to both previous tests.
Test 4
Using sequential Create and Update requests with plugins steps registered on CreateMultiple and UpdateMultiple messages
Operation |
Average |
Create |
55 |
Update |
59 |
When running sequential Create and Update requests, the time is longer than in the case of CreateMultiple and UpdateMultiple (Test 3), but comparable to Test 1, where plugins on Create and Update messages were used.
Final thoughts
Test results show that whenever we’ll need to run bulk create or update operations on Dataverse records, implementing additional logic as a CreateMultiple or UpdateMultiple event handler may be a good choice. Executing mass record operations using plugins on the above-mentioned messages gives us a real performance boost. And because the performance test results for the Create/Update and CreateMultiple/UpdateMultiple plugins are very similar, maybe it is worth considering implementing your business or integration logic with second types of messages also for handling Create and Update events. Just remember that not all the tables support multiple-operations-type handlers. There are also some differences when implementing multiple-operations plugins (for example, accessing record images or error handling). But it is nothing that developers couldn’t figure out.
All the code used for executing tests described in this article may be found on: https://github.com/oneDynamics/blog/tree/main/create-update-multiple-demo/src/Odx.Demo.MultipleEvents