ORM Framework developers have optimized their framework for rare cases. You can see this most clearly with Hibernate. If you want to initialize entities, you must either use an extremely convoluted JOIN FETCH statement, which doesn't really work the way you think it should work and can't be composed, or you choose to use entity graphs, which are a horrific contraption of Java annotations. The Rails style include method is a reasonably sane solution, but again, why can you load that association via lazy loading in the first place? The unpredictable performance of ORMs emerges from the fact that you write a query, which then gets you a hollow shell of an object, containing landmines which can blow up and trigger additional queries, long after the original query. The call to the framework and it's actual communication with the database are temporally disconnected.
N+1 in Ruby on Rails
11–18 of 18 posts
Re: N+1 in Ruby on Rails
#12Any ORM built around implicit lazy loading is doomed. The idea in itself is simply stupid. The ideal usecase for lazy loading is that you have a single object, e.g. a user page and then you never load a collection of objects. The fact that you end up doing a few more queries doesn't matter. ORM Framework developers have optimized their framework for rare cases. You can see this most clearly with Hibernate. If you wan…
Re: N+1 in Ruby on Rails
#13I will never understand why more developers don't just learn effective SQL. In many cases, the database is both the most expensive and most powerful component of the system - may as well put it to use! The N+1 query used as an example in the post could have just been a single query.
There is good value in having ORM for all those boring 90% data fetch tasks. It removes a whole lot of boilerplate and you can guarantee that your code representation equals database representation. The actual problem here lies in the Active Record (anti) Pattern. It becomes impossible to distinguish in-memory access from db access. I’m not surprised to find this being particularly prevalent in dynamically typed scri…
I'm not a big fan of Active Record either, but conflating the two is pretty much the point. I think the biggest antipatterns around AR are in trying to treat it as a transparent abstraction rather than always being aware that it's more or less an "immediate mode" DB interface. Yes, you can treat your model objects as plain old domain objects here and there, but they don't stop being intimately tied to the database at all times, and you need proper DTOs and/or extra interfaces if such separation ever becomes important. But many apps don't have to care, and those are the ones where AR isn't such an albatross.
My main problem with AR is crappy implementations like Eloquent. No identity cache, so many methods and props on the Model base God Class that prevent using a column with that name, magic methods everywhere... Still, it serves all right as long as you treat it as a DB interface and not your canonical business object model.
Re: N+1 in Ruby on Rails
#14I will never understand why more developers don't just learn effective SQL. In many cases, the database is both the most expensive and most powerful component of the system - may as well put it to use! The N+1 query used as an example in the post could have just been a single query.
ORMs, like SQL, C++, Python, and Ruby are just a tool. You can be shit at using that tool. ORMs also usually allow you to drop down to SQL when you have to. They are there to help you, and they expect you to know what you're doing. Like other tools that make so much easy, they do make it easy to shoot yourself in the foot. I won't argue that the average ORM-user is more likely to create shitty-performing code than th…
I've been using sqlc, sqlx, pgtyped, & kysely and I found they have ORM-like productivity with full type-safety but they don't bring the baggage of leaky abstractions.
Unfortunately I don't know if there are Ruby or Python equivalents yet.
Re: N+1 in Ruby on Rails
#15Earlier quoted context omitted.
There is good value in having ORM for all those boring 90% data fetch tasks. It removes a whole lot of boilerplate and you can guarantee that your code representation equals database representation. The actual problem here lies in the Active Record (anti) Pattern. It becomes impossible to distinguish in-memory access from db access. I’m not surprised to find this being particularly prevalent in dynamically typed scri…
> The actual problem here lies in the Active Record (anti) Pattern. It becomes impossible to distinguish in-memory access from db access I'm not a big fan of Active Record either, but conflating the two is pretty much the point. I think the biggest antipatterns around AR are in trying to treat it as a transparent abstraction rather than always being aware that it's more or less an "immediate mode" DB interface. Yes,…
I am super defensive on this one. Apps can keep not caring about it... until they have to.
Is it that much more effort to have a clear boundary between domain and db-access? I think it is only effort if you don't know what you are doing... which is _precisely_ when you need it the most.
> Still, it serves all right as long as you treat it as a DB interface and not your canonical business object model.
I still don't get the benefits. If you decouple db-model from domain model you lose all "advantages" of AR. It's like having plain DTOs but with its sharp spikes sticking out if you ever do something wrong.
Re: N+1 in Ruby on Rails
#16Earlier quoted context omitted.
> The actual problem here lies in the Active Record (anti) Pattern. It becomes impossible to distinguish in-memory access from db access I'm not a big fan of Active Record either, but conflating the two is pretty much the point. I think the biggest antipatterns around AR are in trying to treat it as a transparent abstraction rather than always being aware that it's more or less an "immediate mode" DB interface. Yes,…
> But many apps don't have to care, and those are the ones where AR isn't such an albatross. I am super defensive on this one. Apps can keep not caring about it... until they have to. Is it that much more effort to have a clear boundary between domain and db-access? I think it is only effort if you don't know what you are doing... which is _precisely_ when you need it the most. > Still, it serves all right as long as…
Re: N+1 in Ruby on Rails
#17Earlier quoted context omitted.
ORMs, like SQL, C++, Python, and Ruby are just a tool. You can be shit at using that tool. ORMs also usually allow you to drop down to SQL when you have to. They are there to help you, and they expect you to know what you're doing. Like other tools that make so much easy, they do make it easy to shoot yourself in the foot. I won't argue that the average ORM-user is more likely to create shitty-performing code than th…
Former ActiveRecord & Django ORM enjoyer here. I've been using sqlc, sqlx, pgtyped, & kysely and I found they have ORM-like productivity with full type-safety but they don't bring the baggage of leaky abstractions. Unfortunately I don't know if there are Ruby or Python equivalents yet.
Could you kindly provide some examples of having type-safety and patterns that "feel like" ORM-like productivity, without the baggage?
I'm very interested! I'm a heavy Django user, but I hate dogma, so I'm very willing to try other stuff!!
Re: N+1 in Ruby on Rails
#18Earlier quoted context omitted.
Ex-Rails here. Rails can optionally use SQL migrations, UUIDs for pks, enforce referential integrity with additional options, and create additional indexes easily. The value of ORMs comes in separating domain data modeling from the peculiarities of a DBMS'es SQL flavor. An ORM should be used to automate the commonplace rather than as a substitute for understanding how to manage and operate a DBMS. SQL knowledge is of…
I’m increasingly cold on ORMs existing to abstract away the specifics of your DBMS. In my entire career I think I’ve seen one migration between different databases (MySQL to Postgres), and it was an undertaking despite using an ORM. Where I do appreciate ORMs is in being able to bridge between the relational world of SQL and the object oriented or functional world of the application. Occasionally I’ll decide an appli…
I've always viewed it more as "we can start fresh with another database with ease" and not "we can migrate from a database to another quickly".
And when I say "start fresh", I don't literally mean starting fresh. It can just mean I write my packages (e.g. Django's "Applications") in a database-independent way and whoever ends up using it can use it with whatever DB they have.
Perhaps your vision is indeed what is often sold, though I never saw it that way.