-
Notifications
You must be signed in to change notification settings - Fork 153
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
Optimize OrderedModelBase._wrt_map() - remove unnecessary query #286
Optimize OrderedModelBase._wrt_map() - remove unnecessary query #286
Conversation
the newly introduced OrderedModelBase._wrt_map method gets the value of the fields defined in order_with_respect_to. this forces django to query the object from the database, but only to be used for comparison. It is optimal to just compare the _id instead of the actual model object.
@@ -0,0 +1,37 @@ | |||
# Query count helpers, copied from django source |
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've added this utils file since this package supports django <3.1, and assertNumQueries
was only introduced therein
Firstly - thank you. I really appreciate the diligence it takes to uncover this sort of thing and then to raise it with us. I am happy to merge in the context manager and use it in tests to track this sort of regression. I didn't expect building the We should absolutely try to use the documented I'll take a look at how best to move forward - we could use a test case for This will also improve other callers of |
Looking at our So our
I think I am in favour of updating our docs and raising a Checks |
You're absolutely welcome. I think we can implement the checks to raise the warning, and update the docs first. That shouldn't take a lot of effort to do, while we devise a proper solution on how to improve the From my perspective, mitigating the issue of added SQL queries is CRITICAL. Some poor django app out there using v3.7 this of this awesome library would have its performance impacted, especially if they didn't have any query count tests to monitor their ORM code. Here's a snippet of the test code i have in my project, which we could probably add for the checks.
|
Regarding the double underscore relations, I would suggest not using Top of my head, it would look like something like this:
that's just a rough idea, of course the multiple Personally, this is not an urgent issue for me, since all my usage of the OrderedModel, only has at most 1 |
Very nice - I've converted these to system checks in b416595 (all Errors) as they are a common misconfiguration. There is a legitimate test failure, adding the
Confirmed by trivially reverting the following lines. Changing the keys of the OWRT dictionary likely needs a corresponding change in the admin where they are lifted out into the URL - will look at this later.
|
0aa0fd5
to
b6520cf
Compare
b6520cf
to
048a270
Compare
For now I have added a slow method I've added documentation around the new Checks and if this looks good I'll release it at 3.7.2 |
I agree that admin should be improved later. I've seen first hand how an unsuspecting N+1 in the admin can crash a production environment. But for now, the fix for the wrt is good. I'm good ✅ with your changes, and thank you for adding those django checks! |
I've recently updated the version of django-ordered-model from one of my projects, and noticed that the change from
3.6
to3.7
caused one of my SQL query count tests to fail. After some investigation, I found that there were additional (unnecessary) query caused bywrt_map()
when initializing the instance. Specifically, one (1) SQL query was added for every field inorder_with_respect_to
I found that
wrt_map
gets the actual related object from the database. And the.save()
method compares the value from_original_wrt_map
.Now, I figured, that instead of actually comparing the objects, we could achieve the same result by comparing the
_id
of the fields instead. More in this below.To visualize the problem
Let's use the Answer model from our tests/models.py
Fetching an object from the database yieds:
this is caused by the invocation of
_wrt_map()
from OrderedModelBase.init to define the_original_wrt_map
.Proposed Solution
The changes I've introduced in this PR, uses the field
_id
instead of the related object when building thewrt_map
. This way, the related object is not fetched from the database (if not yet set prior).Caveat: This solution only works for
order_with_respect_to
fields that are actuallyForeignKeys
. As of writing, I have not yet tested it on reverse FK, ManyToMany, etc. I know my changes will not work for these. I'm hoping someone could contribute to solving the problem.Alternate (Temporary) Solution
The easier solution here, and without code change, would be to hardcode
_id
when defining theorder_with_respect_to
. So instead ofwe could define our model:
This of course, requires that we update the documentation, and also assumes that the package user (developer) is aware of this problem, and would require them to update existing code. I would not suggest this as a long term solution.
--
Additional notes:
assertNumQueries
checks on other parts of the tests