Multiple Query, SubQuery, LeftJoinQuery
in Study
Prisma VS TypeORM 을 진행하면서 궁금한 점이 생겼던 걸 찾아보았고, 정리해보았다. (Shout-out to GPT)
Multiple Query, SubQuery, LeftJoinQuery 세 가지를 비교하는데, 이 글만 읽는 사람에게는 Multiple Query는 낯설 수 밖에 없다. 내가 지어냈기 때문이다. 간단하게는 다중 쿼리이다. 이전 게시글에서 Prisma가 사용했던 방식이라고 생각하면 편하다. 다중으로 쿼리문을 던져 Where In 절 같은 문구를 사용해 LeftJoin Query의 결과물과 같은 데이터 조회하는 방식이다.
똑같은 데이터임에도 각각 처한 상황에 따라 성능이 다르단걸 정리해보았다.
Multiple Query
효율이 좋은 경우:
- 병렬 처리 가능성: 데이터베이스가 여러 쿼리를 병렬로 처리할 수 있을 때. 이는 데이터베이스가 여러 CPU 코어를 활용할 수 있을 때 특히 유리하다.
- 네트워크 지연 최소화: 쿼리 결과가 매우 큰 경우, 결과를 부분적으로 가져와 처리하는 것이 더 효율적일 수 있다. 이때 여러 개의 쿼리를 사용하면 네트워크 지연을 줄일 수 있다.
- 캐싱 활용: 첫 번째 쿼리 결과를 캐싱하여 두 번째 쿼리에서 재사용할 수 있을 때. 이 경우 데이터베이스 부하를 줄이고 성능을 높일 수 있다.
효율이 좋지 않은 경우:
- 네트워크 오버헤드: 여러 쿼리를 실행해야 하므로, 네트워크 지연이 큰 환경에서 비효율적일 수 있다.
- 결과 결합의 복잡성: 여러 쿼리의 결과를 애플리케이션 레벨에서 결합하는 것이 복잡하고, 이로 인해 추가적인 메모리와 CPU 리소스가 소모될 수 있다. → Prisma는 애플리케이션 레벨에서 결합을 해준다. 그 과정에서 사용되는 메모리나 CPU 리소스는 무시하지 못하는게 맞는 거 같다.
- 데이터 일관성 문제: 여러 쿼리 사이에 데이터베이스 상태가 변경될 가능성이 있는 경우(트랜잭션 관리가 필요한 경우). 이 경우, 일관된 결과를 보장하기 어려울 수 있다.
서브쿼리
효율이 좋은 경우:
- 단일 쿼리로 문제 해결: 서브쿼리로 모든 데이터를 한 번에 가져올 수 있을 때. 데이터베이스 엔진이 서브쿼리를 최적화하여 효율적으로 처리할 수 있다면, 서브쿼리는 매우 효율적일 수 있다.
- 조건에 맞는 필터링: 서브쿼리를 사용하여 특정 조건에 맞는 데이터를 필터링하는 경우. 예를 들어, WHERE IN (subquery) 같은 경우, 해당 서브쿼리가 작은 결과를 반환할 때는 효율적이다.
- 데이터베이스 엔진 최적화: 서브쿼리를 잘 처리하는 데이터베이스 엔진을 사용할 때. 일부 데이터베이스는 서브쿼리에 대해 매우 효율적인 최적화를 수행할 수 있다.
효율이 좋지 않은 경우:
- 큰 데이터셋 처리: 서브쿼리가 매우 큰 데이터셋을 다루거나, 복잡한 연산이 포함된 경우. 이 경우 서브쿼리가 데이터베이스에 큰 부하를 줄 수 있다.
- 인덱스 활용 제한: 서브쿼리가 인덱스를 효율적으로 사용하지 못하는 경우. 이 경우, 전체 테이블 스캔이 발생할 수 있어 성능이 저하될 수 있다.
- 복잡한 서브쿼리: 서브쿼리가 중첩되거나, 여러 단계의 서브쿼리를 사용하는 경우. 이는 데이터베이스 성능 뿐 아니라, 가독성에도 문제가 생긴다고 생각한다.
LEFT JOIN
효율이 좋은 경우:
- 모든 데이터를 포함해야 할 때: 왼쪽 테이블의 모든 데이터를 포함하고, 오른쪽 테이블에서 일치하는 데이터를 결합해야 할 때. LEFT JOIN은 이 경우 매우 효율적이다.
- 아래 예에서 모든 직원의 이름과 그들이 속한 부서의 이름을 가져오되, 부서가 없는 직원도 포함해서 조회한다.
SELECT employees.name, departments.name FROM employees LEFT JOIN departments ON employees.department_id = departments.id;
- 아래 예에서 모든 직원의 이름과 그들이 속한 부서의 이름을 가져오되, 부서가 없는 직원도 포함해서 조회한다.
- 관계형 데이터베이스 최적화: 두 테이블 간의 관계가 명확하고, 외래 키 관계에 인덱스가 잘 설정되어 있는 경우 LEFT JOIN이 매우 효율적이다. 인덱스를 통해 조인 작업이 최적화될 수 있다.
- 결합된 결과가 작을 때: 조인 결과가 상대적으로 적고, 결합된 데이터의 크기가 작은 경우, LEFT JOIN은 매우 효율적일 수 있습니다. 데이터베이스는 이 작업을 효율적으로 처리할 수 있습니다.
효율이 좋지 않은 경우:
- 큰 데이터셋 간의 JOIN: 두 테이블 모두 매우 큰 데이터셋을 가지고 있고, 결과적으로 결합된 결과가 매우 클 때. 이 경우 JOIN 연산은 데이터베이스에 큰 부하를 줄 수 있다.
- 많은 NULL 결과: 오른쪽 테이블에서 일치하는 데이터가 거의 없어서, 대부분의 결과가 NULL인 경우. 이 경우 JOIN의 효율성이 떨어질 수 있다.
- 인덱스가 부족한 경우: 결합에 사용되는 키에 인덱스가 적절히 설정되지 않은 경우. 이는 성능 저하로 이어질 수 있다.
결론
- Multiple Query는 데이터 접근이 독립적이면서, 데이터베이스 부하를 분산시키고 병렬 처리가 가능할 때 효과적이다.
- SubQuery는 단일 쿼리로 문제를 해결하고, 데이터베이스가 서브쿼리를 효율적으로 최적화할 수 있을 때 좋다. 그러나 큰 데이터셋이나 복잡한 연산이 포함될 때는 비효율적일 수 있다.
- LEFT JOIN은 관계형 데이터베이스에서 최적화된 방식으로 모든 데이터를 포함하고 결합할 때 효율적이다. 하지만 큰 데이터셋 간의 결합이나, 인덱스가 부족한 경우에는 성능이 저하될 수 있다. 각각의 장단점이 분명한 거 같다. 사실 작성하면서도 와닿지가 않는 거 같다. 또한, 쉽게 비교할 수도 없다.
데이터가 어떻게 분포되어있는지에 따라, 인덱싱에 따라, 클러스터링에 따라, 네트워크 지연율 등 너무 많은 변수가 존재하고, 상황에 따라 다르게 사용하는게 맞을것이라 생각된다.