-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(form): optimize calculated question performance #2339
base: main
Are you sure you want to change the base?
Conversation
czosel
commented
Dec 2, 2024
•
edited
Loading
edited
- drop several signals in favor of explicit calls in domain logic to allow reuse of form structure
- add prefetching for document structure
- apply topological sorting before calculating answers on document creation
@czosel Note: Instance creation is still slow, and seems to be triggered by create in SaveDocumentLogic. I'm having a look. |
Form changes (e.g. through form-builder) are probably also still slow. |
This sorts the graph that is formed by calculated questions and their dependents, and then initializes them in the correct order.
a47c6e1
to
33746a0
Compare
4584728
to
d1bd793
Compare
@receiver(post_save, sender=models.Question) | ||
@disable_raw | ||
@filter_events(lambda instance: instance.type == models.Question.TYPE_CALCULATED_FLOAT) | ||
def update_calc_from_question(sender, instance, created, update_fields, **kwargs): | ||
# TODO optimize: only update answers if calc_expression is updated | ||
# needs to happen during save() or __init__() | ||
|
||
for document in models.Document.objects.filter(form__questions=instance): | ||
update_or_create_calc_answer(instance, document) | ||
|
||
|
||
@receiver(post_save, sender=models.FormQuestion) | ||
@disable_raw | ||
@filter_events( | ||
lambda instance: instance.question.type == models.Question.TYPE_CALCULATED_FLOAT | ||
) | ||
def update_calc_from_form_question(sender, instance, created, **kwargs): | ||
for document in instance.form.documents.all(): | ||
update_or_create_calc_answer(instance.question, document) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dropped these two handlers completely. On my local instance, updating a calculated question took about 10s, even though I only had 10 documents in the DB. Since in typical prod scenarios we have thousands of documents, this kind of thing should be done, if needed, explicitly in a management command.
d1bd793
to
ad4d2e7
Compare
calc_question.calc_expression = "'sub_question'|answer -1" | ||
calc_question.save() | ||
calc_ans.refresh_from_db() | ||
assert calc_ans.value == 99 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This functionality was dropped: When updating the calc expression of a calculated question, the answers are not updated automatically anymore.
ad4d2e7
to
55cf7ec
Compare
0426441
to
af7e014
Compare
], | ||
) | ||
) # fmt:skip |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
drive-by fix: exclude this block from autoformatting so that all parametrizations can stay one one line