Fifty one queries. That is what the SQL panel of the Kohana profiler showed for one catalog page. Fifty posts on the page.

Nothing changed in the code. The page took two seconds because there was more data than in spring, and the code was written for spring.

$post->author->name in a loop. One query for the list of posts, then one more for the author of every post, inside the foreach. The line looks innocent, and that is the problem: lazy loading hides the price. You write the relation, you go home early, and the bill comes in six months.

Three ways out.

$posts = ORM::factory('Post')->with('author')->find_all();

with() builds one JOIN and hydrates both objects. Works well for belongs_to. For has_many it is worse, the JOIN multiplies rows and you get the same post ten times.

Second, a manual join with plain result rows. You lose the object model. You get exactly the SQL you wrote, and nothing else. For heavy list pages I prefer this one now.

Third, two queries. Load the posts, collect ids, load all authors with IN (...), map by hand. More code, but predictable. And it works where JOIN does not.

I am not against the ORM. A convenient object model has a price, and the price is written in the SQL log, where the code does not show it. So keep the profiler open while you develop. And watch the query count, not the query time. Time depends on your laptop. Count will be the same in production.

Mine was.