벤치마크: Prisma VS TypeORM

Prisma와 TypeORM은 2022년 JavaScript 생태계의 주요 ORM 선택일 가능성이 있으므로 이 두 도구를 비교하는 성능 벤치마크를 수행하기로 결정했습니다.

메모



이것은 매우 간단한 벤치마크입니다. 이를 위해 방금 console.time와 Excel을 사용했습니다. 잘못된 부분이나 밝혀진 부분이 있으면 알려주세요.

벤치마크 설정



이 벤치마크는 어떻게 만들어졌습니까? 어떤 도구가 사용되었습니까? 어떤 데이터베이스? 나는 이 벤치마크에서 100% 투명하기를 원하므로 이것이 구현된 방법에 대한 모든 세부 사항을 설명할 것입니다.

사용 도구


  • TypeScript - v4.7.4
  • @faker-js/faker - v7.4.0
  • Node.js - v16.14.2
  • Prisma - v4.2.1
  • TypeORM - v0.3.7

  • 데이터 베이스



    도커 컨테이너 내에서 실행되는 PostgreSQL 이미지를 사용했습니다. 하나의 벤치마크와 다른 벤치마크 사이에 가능한 한 적은 간섭을 주기 위해 저는 각각에 대해 별도의 컨테이너에 있는 두 개의 데이터베이스를 사용했습니다.

    테스트 환경



    노트북 델 인스피론 15:
  • 16GB RAM
  • Intel 7 11세대 5.0GHz 옥타코어
  • 512GB SSD
  • NVIDIA® GeForce® MX450, 2GB GDDR5
  • 쿠분투 22.04 LTS

  • 접근하다



    벤치마크는 prisma-benchmark.ts와 typeorm-benchmark.ts의 두 가지 파일로 나뉘었고 한 번에 하나씩 성능을 측정해야 합니다. 이러한 방식으로 벤치마크를 수행하면 데이터베이스에 대한 두 개의 동시 연결, 가비지 수집기 및 CPU 사용량과 같은 외부 요인을 최소화할 수 있습니다.

    벤치마크 코드



    이 벤치마크는 2개의 다른 데이터베이스를 사용하지만 정확히 동일한 테이블인 User 및 User_Address를 사용합니다.

    많은 사용자 만들기



    prisma-benchmark.ts의 "많은 사용자 만들기"코드:

    const createManyUsers = async (count: number) => {
      const fCount = count.toLocaleString('en-US')
    
      const fakeUsers = Array.from({ length: count }, () => ({
        name: faker.name.fullName(),
        email: faker.internet.email(),
        password: faker.internet.password(),
        group: userGroups[Math.floor(Math.random() * userGroups.length)]
      }))
    
      console.time(`Create(many) ${fCount} users - PRISMA`)
      await prisma.user.createMany({
        data: fakeUsers,
      })
      console.timeEnd(`Create(many) ${fCount} users - PRISMA`)
    }
    


    typeorm-benchmark.ts의 "많은 사용자 만들기"코드:

    const createManyUsers = async (count: number) => {
      const fCount = count.toLocaleString('en-US')
    
      const fakeUsers = Array.from({ length: count }, () => ({
        name: faker.name.fullName(),
        email: faker.internet.email(),
        password: faker.internet.password(),
        group: userGroups[Math.floor(Math.random() * userGroups.length)]
      }))
    
      console.time(`Create(many) ${fCount} users - TYPEORM`)
      await userRepository.save(fakeUsers)
      console.timeEnd(`Create(many) ${fCount} users - TYPEORM`)
    }
    


    모든 사용자 찾기



    prisma-benchmark.ts의 "모든 사용자 찾기"코드:

    const findUsers = async () => {
      console.time('Find users - PRISMA')
      await prisma.user.findMany()
      console.timeEnd('Find users - PRISMA')
    }
    


    typeorm-benchmark.ts의 "모든 사용자 찾기"코드:

    const findUsers = async () => {
      console.time('Find users - TYPEORM')
      await userRepository.find()
      console.timeEnd('Find users - TYPEORM')
    }
    


    주어진 조건과 일치하는 사용자 찾기



    prisma-benchmark.ts에서 "지정된 조건과 일치하는 사용자 찾기"에 대한 코드:

    const findByGroup = async () => {
      console.time('Find users by group - PRISMA')
      await prisma.user.findMany({
        where: {
          group: 'guest'
        },
      })
      console.timeEnd('Find users by group - PRISMA')
    }
    


    typeorm-benchmark.ts에서 "지정된 조건과 일치하는 사용자 찾기"에 대한 코드:

    const findByGroup = async () => {
      console.time('Find users by group - TYPEORM')
      await userRepository.find({
        where: {
          group: 'guest'
        },
      })
      console.timeEnd('Find users by group - TYPEORM')
    }
    


    스트레스 시나리오에서 사용자 만들기



    prisma-benchmark.ts의 "스트레스 시나리오에서 사용자 만들기"에 대한 코드:

    const createUsersIntensive = async (count: number) => {
      const fakeUserAddresses = Array.from({ length: count }, () => ({
        address: faker.address.streetAddress(),
        city: faker.address.city(),
        state: faker.address.state(),
        zip: faker.address.zipCode(),
        country: faker.address.country(),
      }))
    
      const fakeUsers = Array.from({ length: count }, () => ({
        name: faker.name.fullName(),
        email: faker.internet.email(),
        password: faker.internet.password(),
        group: userGroups[Math.floor(Math.random() * userGroups.length)],
        userAddresses: fakeUserAddresses
      }))
    
      console.time(`Create users intensive - PRISMA`)
      for (const user of fakeUsers) {
        await prisma.user.create({
          data: {
            ...user,
            userAddresses: {
              create: user.userAddresses
            }
          },
        })
      }
      console.timeEnd(`Create users intensive - PRISMA`)
    }
    


    typeorm-benchmark.ts의 "스트레스 시나리오에서 사용자 만들기"에 대한 코드:

    const createUsersIntensive = async (count: number) => {
      const fakeUserAddresses = Array.from({ length: count }, () => ({
        address: faker.address.streetAddress(),
        city: faker.address.city(),
        state: faker.address.state(),
        zip: faker.address.zipCode(),
        country: faker.address.country(),
      }))
    
      const fakeUsers = Array.from({ length: count }, () => ({
        name: faker.name.fullName(),
        email: faker.internet.email(),
        password: faker.internet.password(),
        group: userGroups[Math.floor(Math.random() * userGroups.length)],
        userAddresses: fakeUserAddresses
      }))
    
      console.time(`Create users intensive - TYPEORM`)
      for (const user of fakeUsers) {
        await userRepository.save({
          ...user,
          userAddresses: user.userAddresses,
        })
      }
      console.timeEnd(`Create users intensive - TYPEORM`)
    }
    



    결과 및 결론





    TypeORM과 Prisma는 "Create Many"시나리오에서 거의 동일하게 수행되었으며 Prisma는 조금 더 빠릅니다.



    TypeORM은 스트레스 시나리오(초당 많은 쓰기 요청)에서 새 레코드를 생성하는 데 훨씬 뛰어난 성능을 보였습니다.



    TypeORM과 Prisma는 "모두 찾기"시나리오에서 거의 동일하게 수행되었으며 Prisma는 조금 더 빠릅니다.



    TypeORM과 Prisma는 "주어진 조건으로 찾기"시나리오에서 거의 동일하게 수행되었습니다.



    Prisma는 읽기 쿼리에서 훨씬 더 빠르게 시작했지만 새 레코드가 데이터베이스에 기록됨에 따라 Prisma는 점차 성능이 저하되었고 TypeORM은 데이터베이스의 1800개 정도의 레코드로 더 빨라졌습니다.

    연결


  • Other benchmark
  • Code that I used to produce this benchmark
  • 좋은 웹페이지 즐겨찾기