데이터 엔지니어링 강의를 듣다가 의문이 생겼다.
다음은 ChatGPT와의 질의응답 내용이다.
Q. nestJS에서 API를 구현할 때, typeORM 쓰는 것과 SQL 쓰는 것에 성능 차이가 있어?
장점:
추상화가 잘 되어 있어서 코드가 깔끔하고 유지보수하기 쉬움
DB 변경 시 유연하게 대처 가능 (예: MySQL ↔ PostgreSQL)
복잡한 관계 설정이나 lazy loading 등 편리한 기능 제공
단점:
추상화 레이어로 인해 성능 저하가 발생할 수 있음 (특히 복잡한 쿼리나 대량 데이터 처리 시)
쿼리가 비효율적으로 생성될 가능성 있음 (join 남발, N+1 문제 등)
장점:
쿼리를 직접 최적화할 수 있어서 성능이 더 좋음
복잡한 비즈니스 로직을 DB 레벨에서 명확하게 표현 가능
단점:
코드 가독성이 떨어질 수 있음
DB에 종속적인 코드가 될 수 있어서 이식성이 떨어짐
보안적으로 SQL Injection 같은 것에 더 신경 써야 함 (라이브러리를 잘 쓰면 괜찮지만요)
단순한 CRUD: 거의 차이 없음
대량 데이터 처리, 복잡한 join, aggregation → raw SQL이 더 빠른 경우 많음
복잡한 로직을 ORM으로 억지로 구현하면 성능이 떨어질 수 있음
기본적인 API는 TypeORM으로 충분하고 개발 효율도 높습니다.
성능이 중요한 쿼리(예: 통계, 리포트, 대량 조회)는 raw SQL이나 QueryBuilder로 따로 빼는 것이 좋습니다.
NestJS에서는 TypeORM과 QueryRunner, QueryBuilder, 혹은 @Query() 같은 방법으로 raw SQL을 함께 쓸 수 있기 때문에 혼용도 가능해요.
Q. QueryBuilder는 TypeORM을 쓰는 게 아니고 SQL문을 쓰는 것과 비슷한 거야?
완전한 raw SQL은 아니지만 ORM의 추상화된 방식보다는 훨씬 구체적인 쿼리 조작이 가능
SQL을 문자열로 직접 쓰는 것보다는 TypeORM의 안전성과 통합성을 유지
| 방식 | 특징 | 장점 | 단점 |
|---|---|---|---|
| TypeORM Entity 방식 | 추상화 높음, 메서드 기반 (.save(), .find()) | 간단하고 유지보수 쉬움 | 복잡한 쿼리에선 불리 |
| QueryBuilder | SQL 구조와 유사하게 쿼리 조립 | 성능 좋고 SQL 구조 파악 쉬움 | 문법이 조금 복잡해질 수 있음 |
| Raw SQL (query() 메서드 등) | 완전한 SQL 문자열 사용 | 성능 최적화 가능 | DB 종속성 ↑, 타입 안전 ↓ |
const users = await userRepository.find({ where: { age: MoreThan(20) } });
const users = await dataSource
.getRepository(User)
.createQueryBuilder("user")
.where("user.age > :age", { age: 20 })
.getMany();
const users = await dataSource.query("SELECT * FROM user WHERE age > $1", [20]);
QueryBuilder는 TypeORM을 쓰는 게 맞지만,
SQL스럽게 직접 조립해서 짜는 방식이라 성능과 유연성 면에서는 raw SQL과 유사합니다.
완전한 raw SQL보다 타입 안전성과 구조적 안정성이 좀 더 좋아요.