typeorm에서 페이징 처리시, distinct 가 실행되는 문제 처리 방법
다음과 같이 typeorm을 사용하여 페이징 처리를 하였습니다.
export class CmtCommentDService {
async getCommentList(searchCommentDto: SearchCommentDto) {
const dataList = await this.cmtReplyDRoRepository.find({
order: { id: 'DESC' },
skip: searchCommentDto.page * searchCommentDto.limit,
take: searchCommentDto.limit,
});
return dataList;
}
}
실형 결과를 보면, 아래와 같이 2회 SQL을 질의합니다.
-- distinct 로 id 조회 처리
select
distinct `distinctAlias`.`CmtReplyD_id` as ids_CmtReplyD_id
from
(
select
`CmtReplyD`.`mod_dtm` as `CmtReplyD_mod_dtm`,
`CmtReplyD`.`mod_sytm_nm` as `CmtReplyD_mod_sytm_nm`,
`CmtReplyD`.`reg_dtm` as `CmtReplyD_reg_dtm`,
`CmtReplyD`.`reg_sytm_nm` as `CmtReplyD_reg_sytm_nm`,
`CmtReplyD`.`use_yn` as `CmtReplyD_use_yn`,
`CmtReplyD`.`id` as `CmtReplyD_id`,
`CmtReplyD`.`cmt_comment_d_id` as `CmtReplyD_cmt_comment_d_id`,
`CmtReplyD`.`cmt_txt` as `CmtReplyD_cmt_txt`,
`CmtReplyD`.`like_cnt` as `CmtReplyD_like_cnt`,
`CmtReplyD`.`pet_user_d_id` as `CmtReplyD_pet_user_d_id`,
`CmtReplyD`.`pet_ccd` as `CmtReplyD_pet_ccd`
from
`cmt_reply_d` `CmtReplyD`
where
`CmtReplyD`.`id` = 10) `distinctAlias`
order by
`CmtReplyD_id` asc
limit 1
-- 실제 데이터조회 처리
select
`CmtReplyD`.`mod_dtm` as `CmtReplyD_mod_dtm`,
`CmtReplyD`.`mod_sytm_nm` as `CmtReplyD_mod_sytm_nm`,
`CmtReplyD`.`reg_dtm` as `CmtReplyD_reg_dtm`,
`CmtReplyD`.`reg_sytm_nm` as `CmtReplyD_reg_sytm_nm`,
`CmtReplyD`.`use_yn` as `CmtReplyD_use_yn`,
`CmtReplyD`.`id` as `CmtReplyD_id`,
`CmtReplyD`.`cmt_comment_d_id` as `CmtReplyD_cmt_comment_d_id`,
`CmtReplyD`.`cmt_txt` as `CmtReplyD_cmt_txt`,
`CmtReplyD`.`like_cnt` as `CmtReplyD_like_cnt`,
`CmtReplyD`.`pet_user_d_id` as `CmtReplyD_pet_user_d_id`,
`CmtReplyD`.`pet_ccd` as `CmtReplyD_pet_ccd`
from
`cmt_reply_d` `CmtReplyD`
where
( `CmtReplyD`.`id` = 10 )
and ( `CmtReplyD`.`id` in (1,2,3,4,5,6,7,8,9,10) )
관련 이슈를 찾아 보니, Typeorm add select distinct in my query. I dont want select distinct. Help!를 확인 할 수 있었습니다.
TypeORM prefers joins, which makes for better performance when pagination is not used.
번역하면, TypeORM은 조인을 선호하므로 페이지 매김을 사용하지 않을 때 성능이 향상됩니다.
으로, 페이징 처리시
에 releation(조인)
처리를 위해서 사용되는 것으로 판된 됩니다.
먼저 id 목록을 distinct
를 이용하여 중복 없는 id
를 조회 하고, 다시 in
id
값을 조회 처리 하여 실제 페이징 이상의 row
를 가져와서 객체를 생성합니다.
하지만, 함께 일하시는 DBA 분의 의견은 distinct
처리로 인해서 되려 성능이 좋지 않다라는 의견을 주셨습니다. Typeorm add select distinct in my query. I dont want select distinct. Help!이 이슈에서도 비슷한 내용이 많이 있습니다.
typeorm에서 페이징 처리시 distinct
을 회피를 아래와 같이 하였습니다.
export class CmtCommentDService {
async getCommentList(searchCommentDto: SearchCommentDto) {
const ids = await this.cmtReplyDRoRepository.createQueryBuilder('cmt')
.distinct(true).distinctOn(['cmt.id'])
.select(['cmt.id'])
.orderBy('cmt.id', 'desc')
.limit(options.limit).offset(options.page * options.limit)
.getMany();
const dataList = await this.cmtReplyDRoRepository.find({
order: { id: 'DESC' },
where: (qb) => {
qb.where(``, { ids: ids.map(i => i.id)})
},
});
return dataList;
}
}
typeorm에서 제공하는 take
, skip
를 사용하지 않고 MYSQL(DBMS)에서 제공하는 limit
, offset
을 사용하여 페이지이 처리를 하면, distinct
호출을 회피가 가능합니다.
또한 relation
이 있을 경우 createQueryBuilder
을 이용해서 id를 먼저 조회하는 SQL을 최적화하여 실행하는 방식을 추천 드립니다.