[TypeORM] Eager Loading, Lazy Loading 및 N + 1

곽태민·2023년 10월 10일
0

TIL

목록 보기
47/63

Eager Loading

Eager LoadingTypeORM에서 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

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

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 쿼리 문제를 최소화하기 위한 전략도 고려해야 한다.

올바른 로딩 방식을 선택하고, 최적화하여 데이터베이스 엑세스 성능을 향상시킬 수 있을 것이다.

profile
Node.js 백엔드 개발자입니다!

0개의 댓글