Eager Loading은 TypeORM에서 Entity 간의 관계를 로드 하는 방법 중 하나로, 만약에 사용자 User
와 그 사용자의 게시물인 Post
간의 관계를 보면
/* User Entity */
@Entity()
export class User {
@OneToMany(() => Post, (post) => post.author)
posts: Post[];
}
/* Post Entity */
@Entity()
export class Post {
@ManyToOne(() => User, (user) => user.posts)
author: User;
}
위와 같이 정의를 하면 자동으로 Eager Loading 설정을 통해 사용자를 검색할 떄, 관련 게시물도 함께 로드할 수 있다.
const user = await userRepository.findOne({
relations: ['posts'],
where: { id: 1 },
});
Eager Loading은 초기 데이터베이스 쿼리에서 모든 관련 데이터를 로드하는 것을 의미한다.
장점은 데이터 로딩 속도가 빠르고, 나중에 해당 데이터 접근 시 추가 쿼리가 필요없다. 하지만 불필요한 데이터 로딩과 메모리 사용량 증가 가능성이 있어서 성능에 영향을 미칠 수 있다.
Lazy Loading은 필요한 시점에서 관련 데이터를 로드하는 방식이다. 이 때, 초기에는 관련 데이터가 로드되지 않는다.
/* User Entity */
@Entity()
export class User {
@OneToMany(() => Post, (post) => post.author)
posts: Promise<Post[]>;
}
/* Post Entity */
@Entity()
export class Post {
@ManyToOne(() => User, (user) => user.posts)
author: User;
}
Lazy Loading 설정을 통해서 사용자를 검색할 때 게시물은 로드되지 않고, 필요한 시점에서 데이터를 로드할 수 있다.
const user = await userRepository.findOne({
where: { id: 1 },
});
const posts = await user.posts;
장점은 초기 데이터베이스 쿼리가 빠르고, 실제로 필요한 경우에만 데이터가 로드되어 메모리 사용량이 줄어든다. 하지만 관련 데이터에 접근 시 추가 쿼리가 필요할 수 있고, 이로 인해 N + 1
쿼리 문제가 발생 할 수 있다.
N + 1 쿼리 문제는 Lazy Loading을 사용할 때 발생할 수 있는 성능 문제다. 예를 들어 사용자 목록을 검색하고 그 사용자들의 게시물 수를 가져오는 경우를 살펴보면
const users = await userRepository.find();
for (const user of users) {
const postCount = await user.posts.length; // 여기서 N + 1 쿼리 문제 발생.
}
이 경우에 사용자 수만큼 추가 쿼리가 실행되어서 성능에 부담을 줄 수 있다. 이 문제를 해결하기 위해 Eager Loading 설정이나 typeorm-query-plan
등을 사용할 수 있다.
Eager Loading을 사용할 때
N+1
쿼리 문제를 피하고 싶을 경우예를 들면, 게시물 목록을 표시하면서 각 게시물의 작성자 정보를 함께 표시하려는 경우 Eager Loading이 유용할 수 있다.
Lazy Loading을 사용할 때**
예를 들어, 대용량 데이터베이스에서 작업할 때 Lazy Loading을 사용해서 초기 데이터 로딩을 최소화하고 필요한 데이터만 로드할 수 있다.
또한 사용자가 특정 데이터에 엑세스할 때만 관련 데이터를 로드하려는 경우 Lazy Loading이 유용하다.
Eager Loading이나 Lazy Loading은 각 장단점이 있고, 프로젝트 요구 사항과 성능을 고려해서 선택해야 한다. 또한 N + 1
쿼리 문제를 최소화하기 위한 전략도 고려해야 한다.
올바른 로딩 방식을 선택하고, 최적화하여 데이터베이스 엑세스 성능을 향상시킬 수 있을 것이다.