-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
⚡ [#5084] Optimize FormVariable.objects.synchronize_for
There are a number of aspects to this performance patch. 1. Avoid database load The UPSERT query when sending all of the desired form variables leads to hefty queries (250ms for 1100 variables, 1100ms for ~7K). Splitting this up in work that can be ignore brings down the query duration to about 50-60ms for 1000 variables. 2. Avoid expensive formio definition processing By far the most expensive operation is scanning whether a component is inside an editgrid ("repeating group") through the utility component_in_editgrid, which was parsing the same configuration over and over again. Instead, we can use the already-existing flag of iter_components to not recurse into edit grids in the first place. This fixes most of the time spent in Python. 3. Replace deepcopy with shallow copy This is probably the most controversial one - when deepcopying a django model instance, it goes through all the motions to serialize it for picking, which means that it must figure out the reconstruction function to use and capture all the necessary data, and deepcopy recurses, which means it also goes into the related form_definition and thus the formio configuration object which is full of lists/dicts that are expensive to deep copy. The replacement with a shallow copy should be fine because: * we're not copying any existing database instances (pk=None) * all the kwargs in initial instantiation are calculated and provided explicitly, there is no reliance on mutation * when 'copying' the desired variables for each form, we assign the optimized form_id attribute and don't do any mutations, i.e. all operations remain on the shallow level This is covered with some tests to hopefully prevent future regressions. Other ideas considered: * don't store FormVariables in the database, but instead create them in memory on the fly. This will be a problem once we no longer store prefill configuration in the component, we will require actual DB instances. It's also not very intuitive * offload to celery again. This is what we initially patched as it was leading to race conditions and dead locks and general performance issues too. It's may also strangely affect existing submissions. Given the complexity and the performance gains, this was not further explored. On my local machine, this brings the worst case insert in the test (1000 form variables from a form definition with 1000 components) from 10+ seconds down to 400ms, so about a factor 25 improvement.
- Loading branch information
1 parent
7c621e4
commit 86b83cc
Showing
2 changed files
with
135 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters