Live data from Hacker News

12 requests per second: A realistic look at Python web frameworks

suade.org

111–120 of 239 posts

Re: 12 requests per second: A realistic look at Python web frameworks

#111
post #37

Earlier quoted context omitted.

Funnily enough, I recently optimized some code along these lines. The way I sped it up was to call `.values()` on the query, which serializes the data into a dict and prevented me from accidentally making subsueqent calls. PS: Indent by 4 spaces for code formatting.

s/ident/indent/

Thanks :).

Re: 12 requests per second: A realistic look at Python web frameworks

#112

My experience doing perf optimizations in real world systems with many many people writing code to the same app is a lot of inefficiencies happen due to over fetching data, inefficiencies caused by naively using the ORM without understanding the underlying cost of the query, and lack of actual profiling to find where the actual bottlenecks are (usually people writing dumb code without realizing it's expensive). Sure,…

There is lots of truth to this. Some ORMs like Django perform joins in very unsuspecting ways. A simple example is, say, foreign keys. Trying to access the foreign key of an object by doing `book.user.id` does an additional query for the user table to get the ID. It's less known that the id is immediately available by just doing `book.user_id` instead. I've spent time optimising things like text searches down from 20…

I encountered this a few times and started adding tests that assert each handler only executes the expected number of queries (and no more). If the application code is modified such that this N+1 query pattern occurs the test will immediately fail and you go optimise the query, problem solved.

https://docs.djangoproject.com/en/dev/topics/testing/tools/#...

Re: 12 requests per second: A realistic look at Python web frameworks

#114
post #80

Earlier quoted context omitted.

> A simple example is, say, foreign keys. Trying to access the foreign key of an object by doing `book.user.id` does an additional query for the user table to get the ID. It's less known that the id is immediately available by just doing `book.user_id` instead. Hmm.. Sounds like a bug. Why is this not the same value for a foreign key?

Well, it is the same value, but the ORM doesn't handle book.user.id any differently than it does book.user.name where it isn't the same value, and thus the only option is to fetch the second table. So it's not a bug, it's really just the ORM being consistent in how it handles queries, thus missing out on a possible optimization in this special case, where a simpler query could have given the same result.

No, that is clearly a bug. The ORM already has the value of book.id, that's how it knows how to fetch the right book. Performing extra queries is just poor implementation.

Re: 12 requests per second: A realistic look at Python web frameworks

#115

Earlier quoted context omitted.

> A simple example is, say, foreign keys. Trying to access the foreign key of an object by doing `book.user.id` does an additional query for the user table to get the ID. It's less known that the id is immediately available by just doing `book.user_id` instead. Hmm.. Sounds like a bug. Why is this not the same value for a foreign key?

Because when you are acessing .user you are asking for all its properties, not just the id. Django does provide relatively easy ways to get over the N+1 issue, though. If you do Book.objects.select_related('user'), only one query is made.

`QuerySet.select_related()` and `QuerySet.prefetch_related()` are the bread and butter of Django query optimisation. I think most of the time that I've noticed a performance issue in our code, it's been easily fixed with one of those.

Re: 12 requests per second: A realistic look at Python web frameworks

#116
post #92

C#/ASP.NET is the fastest web framework now: https://www.techempower.com/benchmarks/#section=test&runid=8... 7.000.000 requests per second Even GO can only achieve 4.500.000 million requests per secnod being a low-level language, in opposite to high-level C#.

C# is only at number 3 in your list. Both Java and Rust are above it in the list. It's also a very "artificial" benchmark and real world code will give different results (if you have static content, just put it in a CDN and don't worry) Other benchmarks from the same site: - JSON Serialization: C# is number 34 - Single query: C# is number 23 - Fortunes: C# is number 7

It needs to be emphasized how artificial these benchmarks really are. Here is the source for the Fortunes C# benchmark:

https://github.com/TechEmpower/FrameworkBenchmarks/blob/mast...

There's no routing or templating, it just writes a bunch of strings. No one would build an actual web app this way.

The only C# benchmarks that are remotely realistic are the mvc variants, starting with aspcore-mvc-ado-pg at number 79.

Re: 12 requests per second: A realistic look at Python web frameworks

#117
post #80

Earlier quoted context omitted.

Well, it is the same value, but the ORM doesn't handle book.user.id any differently than it does book.user.name where it isn't the same value, and thus the only option is to fetch the second table. So it's not a bug, it's really just the ORM being consistent in how it handles queries, thus missing out on a possible optimization in this special case, where a simpler query could have given the same result.

No, that is clearly a bug. The ORM already has the value of book.id, that's how it knows how to fetch the right book. Performing extra queries is just poor implementation.

But it doesn't have book.user itself. Unless you want Django to construct some empty proxy object representing book.user for this one particular optimization.

If it's a bug, sounds like a "wontfix" to me.

Re: 12 requests per second: A realistic look at Python web frameworks

#118

Earlier quoted context omitted.

I increasingly lean towards plain SQL over ORMs. It requires greater familiarity with SQL but I prefer that over greater familiarity with ORM-specific syntax that doesn’t translate across frameworks or languages. In addition, you can prototype new queries and profile existing queries in the database and copy-paste directly into your code.

IMO both are required. I'm lucky in that I did a lot of plain SQL early on, and found ORMs later, but I think ORMs do cut out a lot of time for quick-and-dirty queries that end up not being the bottleneck. The problem arises once you find a bottleneck, you won't know how to optimize it if you haven't done a bit of SQL mucking about earlier. Also, the big thing is you won't know how to translate to other ORMs if you d…

Yeah, ORMs are specifically made for insert-heavy operations or very basic mapping of rows to objects. Analytical queries and the rest should be done with SQL.

Re: 12 requests per second: A realistic look at Python web frameworks

#119
post #66

Earlier quoted context omitted.

if that's your bag then you can still totally do that with an ORM, hibernate for example lets you just write a whole query in raw SQL while still getting all the benefits of eliding a bunch of boilerplate field copying, having "active" objects with ORM-level update/transaction management, etc. plus it means you don't have to write all the dumb "select * from books where bookName = :bookName" code that obviously can b…

We're gradually removing our ORM usage to avoid active objects. They look too much like VSTs, but subtly make foreign network calls when you least expect it, which makes it very hard to write effective, isolated tests or replace the database layer by something else, like a service call or a cache lookup.

I’m sorry if it sounds harsh, but that is the mistake of the developers than. I think you would not allow anyone to write production code without knowing the language; it should be the same way with most libraries, especially ones having a big reach, like ORMs. Nonetheless, I have seen it countless of times in the team I worked in — so it is unfortunately really frequent.

Re: 12 requests per second: A realistic look at Python web frameworks

#120
post #69
post #5

Don't forget that you're paying a huge price using the sqlalchemy orm - https://docs.sqlalchemy.org/en/13/faq/performance.html If I know an endpoint is going to be hit hard, I forgo trying to use the ORM (except to maybe get the table name from the model obj so some soul can trace it's usage here in the future) and directly do an engine.execute( ). Makes a huge difference. Next optimization I do is create stored proc…

ORMs aren't inherently that heavyweight, as a Java developer I don't have performance concerns about hibernate. That sounds to me like a Python problem and a "this specific ORM isn't performant" problem, not ORMs being bad as a whole. Python has never been the fastest language (it's far slower than, say, Java) and the GIL really prevents applications from scaling well without multiple instances. And if you really wan…

Totally agree with you, only want to add that unfortunately the team doesn’t really know the given ORM they use, and I have seen some utterly stupid uses of eg. Hibernate (like eager fetching basically everything there is for queries where it is not required, or simply not knowing anything about the boundaries where an object is “attached” or not). Which one might argue that it is a defect in the tool, but I doubt you would blame an airplane for crashing when the “pilot” is not trained to drive it.
Post reply on HN