ORM Lazy Loading: Defer Queries Until Needed
An ORM's lazy loading fetches related data only when you access it, not with the initial query. This speeds up the first query if you don't need related objects. The footgun is the N+1 problem, where a loop triggers many hidden, slow database queries.
WHY IT EXISTS: To avoid the performance cost of fetching an entire object graph from the database when you might only need the root object. Loading a user and all their posts, comments, and likes is expensive if you only need the user's email address for a mailing list.
THE MENTAL MODEL: Think of lazy loading as an IOU for data. When you fetch a User object, the ORM gives you the user's direct attributes and an IOU for their posts collection. The database isn't queried for the posts until you try to "cash in" the IOU by actually accessing the user.posts property in your code.
HOW IT WORKS: When you query for a primary object, like User.find(1), the ORM returns the user object but replaces its related collections (like posts) with a special proxy object. This proxy knows how to fetch the real data but hasn't done it yet. When your code accesses user.posts, the proxy intercepts the call, runs a new query like SELECT * FROM posts WHERE user_id = 1, populates the collection with the results, and returns it.
WHEN TO USE IT: It's often the default behavior in ORMs and is useful when you frequently load parent objects without needing their children. For example, listing users by name and email without showing any of their posts. It keeps initial queries fast and light by deferring work until it's certain that it is needed.
WHEN NOT TO USE IT: Avoid it when you know you will need the related data. If you're fetching 100 users to display their names and their most recent post, lazy loading will cause 101 separate database queries (1 for users, 100 for posts). This is the infamous N+1 query problem and is highly inefficient. In this case, use eager loading (e.g., with a JOIN) to fetch everything in one or two queries.
ONE CANONICAL EXAMPLE: A web app displays a list of 50 articles with their authors' names. A developer writes a loop: articles = Article.all(). Then in the view template: for article in articles: print(article.title, article.author.name). If the author relationship is lazy-loaded, this code executes 51 SQL queries: one to get all articles, and then 50 more (one inside the loop for each article) to get each author's name. This is a classic N+1 bug. The fix is to eager-load the authors: articles = Article.includes(:author).all().
Read the original → en.wikipedia.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.