Skip to content

Prisma 성능 최적화

Jinho Kim edited this page Jun 22, 2023 · 5 revisions

Prisma 성능 최적화 관련하여 정리한 페이지입니다.

1. Prisma의 쿼리 로깅을 활성화하여 매번 어떻게 쿼리를 실행시키나 확인을 하여 비효율적인 쿼리를 식별할 수 있다.

const prisma = new PrismaClient({
  log: ['query']
});

2. N+1 쿼리 문제 방지

include, select 옵션을 사용함으로써 해결 가능
EX) include를 사용하여 user 테이블과 post 테이블을 조인하여 사용자와 그들의 게시물을 한 번의 쿼리로 가져올 수 있다.

const usersWithPosts = await prisma.user.findMany({
  include: {
    posts: true,
  },
});

3. 배치 처리 및 캐싱

prisma와 dataloader를 같이 사용

4. 필요한 경우 Raw SQL 사용

prisma.$queryRaw 또는 prisma.$executeRaw 메서드를 사용

const result = await prisma.$queryRaw`SELECT * FROM User WHERE email = ${email}`;

5. 데이터베이스 최적화(인덱스 추가)

인덱스는 저장 공간을 차지하고, 데이터가 추가, 수정, 삭제될 때마다 업데이트 해야 하기에 유지 비용이 발생한다.
그렇기에 인덱스를 적용하는 필드가 상당히 중요하다.
아래와 같은 기준으로 필드에 인덱스를 적용하면 좋을 것 같다.

1. 번번하게 조회되는 필드
EX) 이메일로 로그인 정보를 자주 조회하는 경우 email 필드에 인덱스를 생성한다

2. 고유성이 높은 필드
인덱스 효율성은 그 필드의 고유성에 큰 영향을 받는다.
그렇기에 고유값이 몇 개 안되는 필드보다는 고유값이 많은 필드에 인덱스를 생성하는 것이 효율적이다.
EX) 성별과 같이 고유값이 2개인 필드보다는 이메일 같은 필드에 인덱스를 생성하는 것이 좋다.

3. WHERE 절에서 자주 사용되는 필드

4. 정렬에 사용되는 필드
데이터를 특정 필드 기준으로 정렬(ORDER BY)해야 하는 경우 해당 필드에 인덱스를 생성하면 정렬 속도가 향상된다.

// @@index 데코레이터를 통해 인덱스 추가가 가능하다
model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  posts Post[]
  profile Profile?

  @@index([email], name: "emailIndex")
}

6. 원자성 연산 사용

Prisma는 increment와 같은 쓰기 연산에 대해 원자성 연산을 지원한다.
아쉽게도 현재 프로젝트에서는 사용할 경우가 없다

const post = await prisma.post.update({
  where: { id: 1 },
  data: {
    viewCount: {
      increment: 1,
    },
  },
});

7. 트랜잭션 사용

Prisma의 트랜잭션 API를 사용하면 하나의 트랜잭션에서 여러 작업을 동시에 수행할 수 있다

const createUserAndPost = await prisma.$transaction([
  prisma.user.create({
    data: {
      email: "example@email.com",
      name: "Example User",
    },
  }),
  prisma.post.create({
    data: {
      title: "Example Post",
    },
  }),
]);

8. 검색 필드 제한

select 옵션을 사용하여 검색하는 필드를 제한할 수 있다

const users = await prisma.user.findMany({
  select: {
    id: true,
    name: true,
  },
});

9. 페이지네이션

skip과 take를 사용한 페이지네이션을 통해 단일 쿼리에서 반환되는 데이터의 양을 쉽게 제한할 수 있다

const users = await prisma.user.findMany({
  skip: 20,
  take: 10,
});

10. Prisma Client 최적화

Prisma Client는 연결 제한 조정 및 연결 풀 사용 등 성능을 최적화하기 위한 여러 옵션을 제공한다

const prisma = new PrismaClient({
  datasources: {
    db: {
      poolSize: 20,
    },
  },
});