본문 바로가기
NestJS

[NestJS] TypeORM Tips1 (Part 1: Don't use save())

by 개복취 2024. 2. 7.

(해당 포스트는 아래의 내용을 기반으로 작성되었습니다.)

https://dev.to/rishit/optimizing-typeorm-tips-from-experience-part-1-dont-use-save-4ke9 

 

1. save()를 쓰게되면 무엇이 문제인가

2. 왜 나쁜가?
2. 어떻게 고쳐야 잘 쓸 수 있을까?


.save()를 쓰게되면 무엇이 문제인가

Repository 내부의 save는 두가지 역할을 한다. 

  1. (엔티티가) 없으면 생성 (It inserts the entity if it doesn't already exist.)
  2. (엔티티가) 있으면 업데이트 (If the entity exists, it attempts to update the existing one.)

 

그러나 save는 위의 과정이 한번의 실행이 아닌, 다음과 같이 두 단계를 통한 실행과정을 거친다. 

  1. SELECT 쿼리를 실행해서 현재 존재하는 엔티티를 찾아낸다.
  2. 스텝1에서 값을 반환해준다면(값이 존재한다면), UPDATE를 통해 값을 업데이트 해준다.
    그렇지 않다면, INSERT 를 통해 새로운 레코드를 기록한다.

 

왜 나쁜가?

  • 데이터베이스는 전체 컬럼을 2번을 왕복해야한다... DB를 읽어들이는 과정동안 네트워크 지연이 발생하게될 것이다.
  • 또한, 확실하게 삽입 또는 업데이트를 해야하는 경우 굳이 save의 '이중기능'을 사용할 필요가 없을 것이다.
  • ORM이 만들어낸 SELECT 테이블에 대해서 비효율적인 하위 쿼리가 포함되고 있다.

(당연하게도, 100만개 이상의 행에 대한 처리를 해야한다면, save를 사용하는 것은 엄청난 비효율일 것 이다...)

 

이 문제를 어떻게 해결합니까?

insert 또는 update를 사용해서 수행할 작업을 확실하게 정해두는것이 좋다.

 

새로운 사용자 등록(insert)

const user = this.userRepository.create({
    name: "Rishit",
    password: "test123",
});
await this.userRepository.insert(user);

 

기존 사용자 업데이트(update)

await this.userRepository.update({
    name: "Rishit",
},{
    name: "John",
});

 

데이터베이스 부하를 줄여 성능을 2배 향상시킬 수 있다. 

 

+추가)

그럼에도 save를 사용해야 하는이유가 있다면?

 

1. save 메소드는 트랜잭션을 통해 작업을 수행하기 때문에 느리지만 안전하다.
쿼리 하나라도 잘못되면 데이터가 삽입되지 않기 때문에 데이터 무결성에 매우 중요한 역할을 해준다.

 

2. save는 사용자 엔티티를 등록할 때 매우 유용한 리스너를 지원한다. (@BeforeInsert 등..)
이를 통해 간단히 사용자를 생성할 수 있다.

 


요약하자면...

create

  • 엔티티 객체 생성, 단순 객체 생성일 뿐, DB로 쿼리문을 요청하진 않는다.
  • 비동기적으로 동작하지 않는다.

insert

  • insert 쿼리 후 select 쿼리를 실행한다.

save

  • 쿼리 조회 후 삽입 또는 수정. SELECT 결과에 따라 INSERTUPDATE 쿼리를 실행한다.
  • typeorm save() 대신 insert()update() 명시해서 사용하기 불필요한 쿼리를 줄일 수 있음, 빠르고 간단하게 데이터 처리.

typeorm save() 사용하게 되는 경우는?

  • (때에 따라) 트랜잭션을 신경 써 줌.
  • 실제로 쿼리 처리에 문제가 생기면 데이터 처리가 rollback됨. 느리지만 안전하게 데이터 처리.