Live data from Hacker News

Ban 1+N in Django

suor.github.io

101–110 of 153 posts

Re: Ban 1+N in Django

#101
post #99

Earlier quoted context omitted.

Would GraphQL be a good starting point for such a language?

It was sarcasm, he was referring to SQL lol

select_related in Django does this. There's also prefetch_related in Django which is not something that is easily done in standard SQL.

Re: Ban 1+N in Django

#103
post #79

Rails has Bullet[0] to help identify and warn you against N+1 Does Django have anything active? Quick search revealed nplusone[1] but its been dead since 2018. [0] https://github.com/flyerhzm/bullet [1] https://github.com/jmcarp/nplusone

There is django-zen-queries[0], mentioned in another comment. [0] https://github.com/dabapps/django-zen-queries

Not a fan of this one since it only works on templates and requires special code

Re: Ban 1+N in Django

#104
post #54

I wonder why ORMs still(?) work as simple wrappers and never track access patterns. If you see that `in books` generator’s results experience accesses through a relationship, it’s pretty obvious to join it in advance after few misses and serve `book.author.full_name` from cache. Of course that would make ORM more complex, but why would you need one otherwise. A good database interface should make good guesses, probab…

I don't want my app to change performance-sensitive behavior at runtime, that's a debugging nightmare. I do want my framework to throw an error in development mode if I screw up the preloading.

Since this also requires the same heuristics, it could be just an option: orm.unroll(“auto|throw|none”). Would suit you, me and a commenter who wants hundreds of requests as they wrote.

Re: Ban 1+N in Django

#105
post #77
post #54

I wonder why ORMs still(?) work as simple wrappers and never track access patterns. If you see that `in books` generator’s results experience accesses through a relationship, it’s pretty obvious to join it in advance after few misses and serve `book.author.full_name` from cache. Of course that would make ORM more complex, but why would you need one otherwise. A good database interface should make good guesses, probab…

I dont know any of this but doesn't the OP give a solution similar to this https://github.com/Suor/django-cacheops

It’s hard to tell by skimming through the readme, but it seems there’s no mention of this technique.

Re: Ban 1+N in Django

#106
post #77
post #54

I wonder why ORMs still(?) work as simple wrappers and never track access patterns. If you see that `in books` generator’s results experience accesses through a relationship, it’s pretty obvious to join it in advance after few misses and serve `book.author.full_name` from cache. Of course that would make ORM more complex, but why would you need one otherwise. A good database interface should make good guesses, probab…

I dont know any of this but doesn't the OP give a solution similar to this https://github.com/Suor/django-cacheops

cacheops is more of a general purpose ORM caching with automatic invalidation.

Re: Ban 1+N in Django

#107
post #79

Earlier quoted context omitted.

There is django-zen-queries[0], mentioned in another comment. [0] https://github.com/dabapps/django-zen-queries

Not a fan of this one since it only works on templates and requires special code

Never used this, but I see that it provides a context manager/decorator, which you can use to "shield" any code. And also some shortcuts for DjangoREST or something.

Regarding extra code, you can simply replace the Djangos' `render()`, with the one from this lib and you are done. I would have probably made a custom template extension or something to do that for all renders automatically though too.

Re: Ban 1+N in Django

#108
post #92

Earlier quoted context omitted.

So, in other words, you want GraphQL.

A dataloader sort of pattern tends to be on the implementing end of GraphQL.

Indeed, the parent was describing built-in features of the Apollo GraphQL Client, such as entity-level caching in the frontend.

However, a dataloader pattern can also be useful when implementing custom resolvers for a GraphQL API. For this purpose, Apollo provides data sources which handle caching at request level.

Re: Ban 1+N in Django

#109
post #101
post #99

Earlier quoted context omitted.

It was sarcasm, he was referring to SQL lol

select_related in Django does this. There's also prefetch_related in Django which is not something that is easily done in standard SQL.

[deleted]

Re: Ban 1+N in Django

#110
post #7

There is a case where having N+1 queries are beneficial. In Rails terms, it's when you perform Russian doll caching, but you can do this in any framework. The idea is you can cache a specific X thing which might make a query to an associated Y thing. A textbook N+1 query case (ie. a list of posts (X) that get the author's name (Y)). If you render the view without any cache with 10 things then you'd perform 20 queries…

Right. Or just let the DB do the caching. If you're not making million user app or have hundreds of gigabytes to query it will be faster than anything done in Ruby code anyway.

> If you render the view without any cache with 10 things then you'd perform 20 queries but after the cache is warm you'd perform 0 queries. If item 5's Y gets updated then you only need to bust the cache for item 5 and query only item 5's Y association. Performing a preloaded query to get all X 10 things with their Y associated things could be an expensive query.

So instead of "do one query to the database, zero if cache is hot, one query again if you invalidate it", you do 20 queries, zero if cache is hot (but 20 cache queries), then 1 if you invalidate it.

That's nice method when single entry query is very expensive but in most cases it will be living in DB cache already.

It is only a win if DB is the bottleneck which by far is rarer case nowadays than RTT. Also you could just query all 20 records at once but write it to cache as separate records, then have write-thru logic for updating records. Best of both at cost of some complexity.

You can also just... cache the resulting page instead of data-level caching, and not engage app code in most requests in the first place. Partial caching with ESI is also possible although pretty involved.

Post reply on HN