프로젝트를 진행하다 보면 다양한 모델을 다루게 되고, 각 모델의 Entity 는 여러 column으로 구성되어 있다.
하지만 이곳에 있는 column들을 항상 A-Z 까지 전부 쓰는 것은 아니고, 상황에 따라 A-C 까지 혹은 D-F 까지 부분만 호출하여 사용하는 상황도 많다. 그동안 JPA, QueryDSL 을 이용해 Repository 에서 Etity 를 호출한 뒤 Response 양식에 맞춰 필요한 부분만 return 하고 있었던 작업은 나머지 데이터까지 불필요하게 호출하고 있었던 것이다.
이에 Projection 이란 기법을 적용하여 효율적인 데이터 전송을 구현해보려 한다.
'투사' 라는 뜻으로 수학에선 아래와 같은 의미로 쓰인다.
사영 또는 투영으로 불리며, 어떤 집합을 "부분집합"으로 특정한 조건을 만족시키면서 옮기는 작용이다. 수학에서 사영은 집합(또는 다른 수학적 구조)을 하위 집합(또는 하위 구조)으로 멱등적으로 매핑하는 것이다.
즉, Entity 모든 column 을 호출해서 사용하는 것이 아니라 필요한 "부분집합" 을 추려서 필요한 데이터만을 가져오므로 데이터 전송을 최소화 하여 성능을 향상시키려는 아이디어인 것이다.
+ 뿐만 아니라 필요한 데이터만 노출하기 때문에 보안성도 강화된다!
그리고 Entity 를 그대로 조회하는 것에는 또 다른 문제가 있다. 조회된 모든 Entity 는 강제로 영속성 컨텍스트의 관리를 받게 된다. Dirty Checking 을 위해 Entity 의 상태를 추적하고, 변경을 자동으로 감지한다는 것인데, 이 부분도 성능 및 메모리에 영향을 주기 때문이다.
따라서 쓰기(Command) 작업을 수행할 땐 Entity 로 조회하는 것이 필요하지만 읽기(Query) 작업을 수행할 땐 Projection 을 통해 필요한 정보만 조회하기로 하는 것이다.
DTO(Data Transfer Object) 는 말 그대로 데이터를 옮기기 위해 존재하는 객체로, Projection 을 통해 데이터를 조회한다는 것은 반환 자료형으로 Entity 가 아닌 DTO 를 사용한다는 것이다.
Projection 은 두 가지로 구분된다.
그리고 구현 방법에도 두 가지 방법이 있다.
여기에 적용할 수 있는 Dynamic Projection 도 있는데, 제네릭을 이용하여 전달받는 클래스의 타입에 따라 반환타입이 달라지게 하는 방법이다.
두 방법 모두 번거로운 과정이 필요하기 때문에 QueryDSL 에서 사용해보려 한다.
QueryDSL 에서 Projection 을 구현하는 방법은 총 4가지 이다.
하지만 약간의 단점이 존재한다면
+ 이후 반환된 DTO 에 맞는 Response DTO 를 생성하여 반환해주면 된다.
+ Projection 이용하면 Covering Index(쿼리의 결과를 인덱스만으로 얻어내어 디스크 I/O를 최소화하여 쿼리 성능을 향상시키는 기술) 를 활용할 수 있다. 이 내용은 조금 더 공부가 필요할 것 같다.