[파이썬] SQLAlchemy Eager Loading vs. Lazy Loading

When working with databases in Python, SQLAlchemy is a powerful and popular choice. It provides an Object-Relational Mapping (ORM) toolkit that allows developers to interact with the database using Python objects.

One important concept to understand while using SQLAlchemy is the difference between eager loading and lazy loading. These two loading strategies determine when and how the related data is fetched from the database.

Lazy Loading

Lazy loading is the default loading strategy in SQLAlchemy. With lazy loading, related data is not loaded from the database until it is actually accessed. This means that when you retrieve an object from the database, its related objects are not immediately loaded.

For example, consider a User class with a relationship to a Post class in which a user has many posts. With lazy loading, when you query a user from the database and access its posts attribute, the related posts are loaded at that moment.

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    posts = relationship("Post", backref="user")

class Post(Base):
    __tablename__ = 'posts'

    id = Column(Integer, primary_key=True)
    title = Column(String)
    user_id = Column(Integer, ForeignKey('users.id'))
# Retrieve a user from the database
user = session.query(User).filter(User.id == 1).first()

# Access the posts attribute, triggering lazy loading
user.posts

By default, SQLAlchemy performs a separate query for each lazy-loaded attribute, which can lead to the N+1 query problem if not managed carefully.

Eager Loading

In contrast to lazy loading, eager loading allows you to load the related data from the database in a single query, upfront. This can be more efficient and avoids the N+1 query problem.

SQLAlchemy provides two ways to perform eager loading: using joinedload or subqueryload. joinedload performs a join query to fetch the related data, while subqueryload performs a subquery to retrieve the related data.

To eager load the posts attribute of a user, you can modify the query as follows:

from sqlalchemy.orm import joinedload

# Retrieve a user from the database and eagerly load the posts attribute
user = session.query(User).options(joinedload(User.posts)).filter(User.id == 1).first()

Now, when you access user.posts, SQLAlchemy will not generate additional queries since the related data has already been fetched.

Conclusion

Understanding the difference between eager loading and lazy loading is crucial when working with SQLAlchemy and databases. Lazy loading provides convenience but can lead to performance issues if not managed carefully. On the other hand, eager loading can optimize query performance but adds complexity to the initial query.

It is essential to analyze the usage patterns and performance requirements of your application to decide when to use eager or lazy loading with SQLAlchemy.