3 ms·
I wonder how many hidden n+1 problems there are. Reading the blog post, it looks like they mostly only tested existing pathways as part of the migration. Who kn
by latchkey 3y ago
I wonder how many hidden n+1 problems there are. Reading the blog post, it looks like they mostly only tested existing pathways as part of the migration. Who knows what random requests could do.
- gavinray 3y agoThis is Netflix, not some amateur-hour implementation copied from a blogpost. The de-facto GraphQL Java library comes with dataloaders built-in anyways: https://www.graphql-java.com/documentation/batching/ https://www.graphql-java.com/documentation/batching/
- voz_ 3y agoWhile Netflix has a good reputation, we should not give blanket benefit of the doubt, especially since the parent comment was a rather interesting and inquisitive one.
- rand_r 3y agoYes, this is the biggest problem with GraphQL that I haven't addressed anywhere. The architectural beauty of GraphQL is that you can write isolated, functional nodes that only have to know about their object type. For example, the User node only has to know how to get the user's last_login, active status, and return a reference to another node type like a profile Image. Inside the User node, you are free to write code (e.g. Java or Python) that can compute which Image node is the right one to return. i.e. you can write: class UserNode: def get_user_profile_image() -> ImageNode: return some_arbitrary_function() There is no way I've seen to square this kind of arbitrary node computation with the desire to write an optimized SQL query that selects all needed information in one big-ass statement.
- valenterry 3y agoThe exact same problem exists in an typical REST api as well. In both cases you have to add a specialized endpoint to retrieve multiple results.
- striking 3y agoYou could use https://github.com/join-monster/join-monster https://github.com/join-monster/join-monster, but setting that aside it's usually enough to use Dataloaders that resolve based on some source ID, with some server-local caching on top if latency becomes an issue.
- 727374 3y agoDataloader (https://github.com/graphql/dataloader https://github.com/graphql/dataloader) eliminates many n+1 issues. Basically, entity requests are queued up during evaluation of the query and then you can batch them up for fulfillment. It’s a great addition to other asynchronous contexts as well. WRT random requests, there are libraries for query cost estimation you can use as a gate.
- theptip 3y agoInteresting, hadn’t seen that package, thanks. The general pattern seems quite useful, is it implemented in any SQL ORMs? Seems like you could do the same batching/coalesce strategy for async Postgres for example, but I don’t see anything after a quick scan of the docs in SQLAlchemy. (Seems like it would be feasible since they already batch requests in unit-of-work, they just don’t coalesce to bulk operations AFAICT.)
- IceDane 3y agoUsing something like `pothos` for your graphql backend, you can get tight integration with `prisma`, which will practically eliminate any N+1 issues. For fields which hit external services, you can define types as "loadable" so that every time those are requested in a batch, they are loaded efficiently to avoid n+1.
- latchkey 3y agoCorrect, there are solutions out there, but unknown if they implemented them.