4 ms·
Which n+1 problems doesn't dataloader solve?
by scottmf 9y ago
Which n+1 problems doesn't dataloader solve?
- foota 9y agoYou don't have to worry so much about n+1 (once you're using dataloader) as much as you do deeply nested queries, or queries that run against a large number of datatypes.
- ruslan_talpa 9y agoi am not sure i follow, the deeper the query or bigger the returned dataset, the worse the performance of a dataloader type solution (see my other comment).
- foota 9y agoWe're agreeing here, I think. I'm saying that after taking care of the n+1 problem by using dataloader, you still have to worry about deeply nested queries.
- andrewingram 9y agoThis is true, but most complex UIs tends to result in queries that spread wide rather than deep. It takes some deliberate contrivance or fairly unusual real-world cases to get to more than 3-4 levels of nested relationships, and this is often the point at which you'd be thinking to deferred/lazy loading in the client anyway. I've spent a significant amount of time over the last year or so optimizing GraphQL servers built on domain-driven services (i.e. joins aren't an option) and managed to get to equal (or very marginally worse) performance to existing handcrafted endpoints that returned equivalent data (it was possible to build the same UI, even though the payloads weren't identical). There are areas where GraphQL is inherently inefficient (trying to work on ways to mitigate these issues), but the reality is that deeply-nested UI appears to be less of a problem than I originally thought it would be.
- ruslan_talpa 9y agoIt eliminates n+1 but not in a perfect way. If you have a 3 level query (3 tables), the best you can hope for is to get 3 sequential queries, like get first level, collect the ids, request the second level, collect the ids, get 3rd level. It gets even more complicated teh more levels you and the bigger the dataset returned. all of this can be done using a single join which is one roundtrip and it's faster.
- raarts 9y agoThank you, thank you. A critical piece of information.
- mambodog 9y agoIf you have low latency queries (eg. because most things hit cache rather than db) sequential queries aren't as much of a problem. Being able to join everything into one query, on the other hand, is a luxury which can be hard to maintain at scale. In the 'join in SQL' case you could identify particular cases which are doing sequential queries and implement a different loader which just does one. It's not automatic but perhaps in most cases it's not necessary to do this step anyway. In the worst case you're back to doing as much work as you would for a bespoke API endpoint, but that's not the typical case. How much of a problem this ends up being in practice very much depends on the type of app you're building and how you intend to scale it.
- ruslan_talpa 9y agoSaying join is a luxury is a dangerous thing :) (for impressional devs :)) 99% of projects are not "at FB scale" :) so join is exactly the right thing to use, it's been tuned over decades so until your scale/dataset does not outgrow one box (and there are big boxes now), you are not going to do a better job then the query optimiser (cause after all that is what you are trying to do).
- mambodog 9y agoFair enough. What I'm trying to get at is that you need to pay attention to the cost of the real world queries which are actually being executed against your API, and then optimize. I'm not sure that SQL is a magic bullet there either (you can still request too much data at once, for example). In practice this probably means adding some logging of how long requests take and graphing it (say, 95th percentile request time) from time to time to spot pathological queries. Even better if you can automate it. I think this is stuff that everyone should be doing (after a certain stage), regardless of whether you are using GraphQL or a bespoke JSON API.