-
Notifications
You must be signed in to change notification settings - Fork 769
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
select_related
and prefetch_related
#57
Comments
Is anyone currently working on this? |
I noticed in the docs on filtering with django_graphene you can define a resolve_xxxx function that returns a queryset. The example they provide is about filtering, but I think you could apply the select_related and prefetch_related modifications here as well. from graphene import ObjectType
from graphene_django.filter import DjangoFilterConnectionField
from .models import Teams
class Query(ObjectType):
teams = DjangoFilterConnectionField(CategoryNode)
def resolve_teams(self, args, info):
return Team.objects.all().prefetch_related('members') http://docs.graphene-python.org/projects/django/en/latest/authorization/#queryset-filtering-on-lists |
I have some code which does some intelligent selective application of database optimisations. This version was written against graphene 0.X and is presented without any kind of guarantee. As and when I miraculously have time to work on it, I'd love to formalise this and get it working in a general case, but I've been saying that for about 9 months now so don't hold out hope. The core idea is to add Note that it also makes use of https://github.com/photocrowd/django-cursor-pagination I'm in the middle of trying to do a graphene 1.0 update on a fairly large and complex API which hit a bunch of internals, it remains to be seen how well this approach holds up with graphene 1.0. However, I hope it is a somewhat useful start for anyone wanting to work on this. https://gist.github.com/mjtamlyn/e8e03d78764552289ea4e2155c554deb |
I've updated the patterns in my gist to make more sense with Graphene 2.0. It also now includes a few additional features including manual post-processing functions and nested fields. This code with a health warning - it definitely makes my API faster because it saves thousands of queries, however I think it may also be the source of some raw python performance issues which is preventing further optimisation of the code. I'm also not yet running it in production, and it is only tested on Python 3. |
Hi all! I've been working on a library that tries to optimize the query by analyzing the gql query: https://github.com/tfoxy/graphene-django-optimizer Feel free to open issues if your use case doesn't work. |
I think |
Gj, everyone. Just a quick question: is there a performance drawback if I simply do a prefetch_related on any FK fields in my model? Because I just tried It seems both update: It kind of did work with DjangoFilterConnectionField if I provide a class Query:
def resolve_listings(self, info, **kwargs):
# this will play nice with DFCF |
You'd probably be For small models, with few relations, and little data, this is probably fine to just do, but otherwise you may want to be smarter about when to add these queries, by using something like |
I found this PR on Sailor https://github.com/mirumee/saleor/pull/2983/files, I personally tried |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
@sliverc is there any reason why you can't use the https://github.com/tfoxy/graphene-django-optimizer library? I'd like to avoid including more code into the library (that needs to be maintained) if there are alternative ways of doing it. |
@jkimbo Secondly I see your point that you want to avoid adding code into the library when possible. In this case I don't see this issue as a feature though but a bug or a instability within graphene-django. Graphs are prone to query explosions and it is quite easy when using the full featureset of |
@sliverc I agree that “query explosions” are likely to happen however I think it is a hard problem and one that won’t necessarily be made easier by building an optimiser into the library. Having said that if you want to create a PR that adds optimisation features into graphene-django I will happily review it. @tfoxy as author of the graphene-django-optimiser library what do you think? Should the library be integrated into graphene-django? Or are there things that we could do to make optimisations easier? |
graphene-django-optimizer was created as a hotfix to improve the performance of the project I was working while not making the codebase uglier (before this, we were making the optimizations at the root of every graph resolver). Maybe the best would be to find a way to make graphene more extensible so this kind of plugins can be better maintained. As I said, I'm no longer working with Django, but I can help to discuss and propose making some changes to this repo. |
Thanks for the reply @tfoxy . Sounds like you are right @sliverc , we should try and integrate some optimisations into graphene-django so that it is maintainable in the long run. I'm going to pick up #250 since it looks like a simple one. Do you have any time to work on adding other optimisations @sliverc ? |
Or @tfoxy if you’d like to merge some of your code into graphene-django that would be very helpful! |
You are most correct, we have to remember the end goal is to have a workable, production-ready API out of the box, or people are going to move to Node. Maybe we should have a vote on the top priority features and I think optimization will be on top1-2. Sadly it is also one of the hardest. The situation may be made better with the planned release of a better async core of |
@jkimbo I have posted here as stale bot was about to close this issue and I wanted avoid this and restart the discussion whether this is a valid issue. I would love to work on this but I am very tight on time. Someone of our team might be able to work at it later on but do not know when this might happen. But could you add |
OK thanks @sliverc . If anyone else would like to work on adding some optimisations to graphene-django that would be great! |
I would like to contribute also
…On Thu, 1 Aug 2019 at 08:56, Jonathan Kim ***@***.***> wrote:
OK thanks @sliverc <https://github.com/sliverc> . If anyone else would
like to work on adding some optimisations to graphene-django that would be
great!
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#57?email_source=notifications&email_token=AAJ5VKWIVY7N2SOH5FZJZELQCKJLJA5CNFSM4CWC3CXKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD3JV6GY#issuecomment-517168923>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAJ5VKSD22QEOLQEQWCDCTDQCKJLJANCNFSM4CWC3CXA>
.
|
I can contribute. I have two questions before doing anything:
I'm not sure when is v3 planned and if it would change much of underlaying code. |
I am not expecting a huge amount of changes needed with v3 since the major breaking change is the dropping of Python 2 and the upgrade of graphql-core. I would suggest that any optimisation improvements could be based off v2.
Since we're going to start building in query optimisations in the library I don't think there is any need to follow the api of @tfoxy @mohamedrez I'm not sure how to break this task down into multiple steps really. @tfoxy any suggestions? |
Just a heads up @tfoxy @mohamedrez that I've had to give up on trying to automatically apply You might find that trying to automatically applying query optimisations has similar issues where they can actually make performance worse in some cases. |
I had the same problems with In the following days, I will try to write about the thinking behind the implementation of graphene-django-optimizer and some suggestions about how to proceed by doing small steps. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Any update on these efforts? |
it would make sense reopening this |
Any status update here? |
feels like graphene has been totally abandoned unfortunately |
I reopened issue and i agree it is not resolved, but please don't assume there will be any development 🙁 |
Is Graphene abandoned? |
at the time when this ticket was created there were no dataloaders. |
i think this repo can be helpful for this issue: https://github.com/MrThearMan/graphene-django-query-optimizer |
Hi, author of graphene-django-query-optimizer here. My library is mostly a rewrite of graphene-django-optimizer, which I found didn't work anymore (although I cannot be 100% certain I set it up correctly 😅) While it is my code, I think the rewrite is more maintainable. Still, there is quite a bit of complexity, rough edges, and ugliness in order to make everything work. It's also quite new and isn't nearly battle-tested enough. I'll address some of the issues raised in this thread, and how my rewrite deals with them:
At the moment, I've found that the optimization works well for model fields and resolvers, even with deep queries. However, there can be issues with custom non-model field resolvers in cases where those resolvers require some model fields that aren't requested in the original query. In regards to canceling the only optimization like the original does in some cases, the rewrite doesn't do this, since I haven't found it necessary, given the above. I did add a setting to disable it globally in case some edge case was found.
In the rewrite, the optimization does also work with connection fields, although it did require some ugly custom resolver logic. The main issue was that caching the query results cannot happen during the initial optimization process, since the connection field applies additional pagination limiting to the queryset, which will limit the number of rows returned from the database. Otherwise, we would cache all rows on the model, which would cripple performance.
Defining a custom There are also some other ugly bits, like how the optimized data is cached between ObjectTypes, but I won't go into the details here. I'm writing all of this to say that while it would be nice to see some query optimization stategy integrated to graphene-django, it would still require considerable effort in testing and deciding on edge cases for something that would be the "official" solution. Still, I'm ready to help if there is interest. |
Thanks, @MrThearMan, for all the insides. I also agree that it's nice to have some formal way of automatic optimizations; we should be careful about the effort required and not to re-invent things that have already been perfected by other other tools. |
The problem with this is that Graphene 3 broke dataloaders. |
When I inspected the actual SQL queries being run against DB, I found that for foreignkey and manytomany relationships, we have the
n+1
problem.For example, suppose there are 5 teams, each with 11 members, this query:
will result in 1 query for selecting
teams
, and 5 more queries for selecting members of each team. 6 queries in total.Normally, we would do a query like this
Team.objects.all().prefetch_related('members')
to reduce to 2 queries.I think it would be extremely beneficial if
DjangoObjectType
can detect special fields:and apply appropriate
prefetch_related
and/orselect_related
when such fields are present in graph queries.The text was updated successfully, but these errors were encountered: