엑셀변환기능 속도향상 시킨 방법

flobeeee·2021년 8월 15일
0

시행착오

목록 보기
18/43
post-thumbnail

🚴‍ 구현한 기능 소개

이름	| 이메일			|블로그			| ...
김OO	| user@gmail.com	|https://velog.io/@user	|...
이OO	| -			|https://velog.io/@test	|...
박OO	| person@gmail.com	|https://velog.io/@person|...

위와 같은 내용이 작성되어 있는 엑셀파일을 아래 처럼 바꾸는 기능이다.
(회사에서 진행한 거라 다른 내용으로 대체해서 설명하겠다)

이름	| 이메일			| 인덱스	| 게시글 수
김OO	| user@gmail.com	| 2	| 34
박OO	| person@gmail.com	| - 	| -

인덱스와 게시글 수는 해당 유저의 정보가 데이터베이스에 있는 경우만 추가된다.
데이터베이스에 정보가 없는 경우 - 표시를 넣었다.

테스트파일로 3,400행까지 리스트가 채워진 파일을 받아서 진행했다.

🚴‍ 처음 작성한 로직 (시간초과)

excelJS를 활용했다.
쉬운 설명을 위해 변환 전 파일을 A파일, 변환 후 파일을 B파일이라고 칭하겠다.
이메일이 있는 경우에만 B파일에 적기 위해 새로운 파일을 만드는 걸로 진행했다.

  1. A파일의 이메일 열을 순차적으로 확인해서, 이메일이 있는 경우 B파일에 이름와 이메일을 적는다.
    (이메일이 없는 경우 다음 행을 확인한다.)
  2. 해당 이메일로 데이터베이스에 정보가 있는지 확인한 후, 있으면 B파일에 추가로 적는다.
    (데이터베이스에 정보가 없는 경우 - 로 표기한다.)
  3. A파일의 리스트가 끝날 때까지 반복한다.

결과
로컬에서 테스트파일로 진행하니 3~4초만에 완료됐다.
배포한 후에 테스트파일로 진행하니, 시간이 너무 오래걸려서 canceled 됐다.
2000개의 행까지 줄여서 진행하니, 45초의 기간이 소요됐다. 너무 오래걸렸다.

🚴‍ Promise.all 적용

for문은 이전 작업이 끝나야 다음 작업을 할 수 있다.
Promise.all 을 사용하면 이 작업을 병렬적으로 처리할 수 있다.

await Promise.all([
  3초 걸리는 작업,
  2초 걸리는 작업,
  4초 걸리는 작업,
])

이렇게 넣어주면 총 4초가 걸린다.

🚴‍ A파일의 데이터를 변수에 모두 넣기

엑셀을 하나확인하고 다른 엑셀에 기입하고, 또 그다음 중 엑셀을 확인하는 작업이
시간소모가 크다는 의견이 있어서 변수에 모두 할당해서 처리하기로 했다.
배열을 만들어서 이메일이 있는 경우에만 해당 데이터를 push했다.

결과
로컬에서 테스트할 때는 시간이 좀 1초정도 줄어들었다.
배포한 후 테스트파일로 진행하니, 같은 현상이었다.

🚴‍ 데이터베이스에 인덱스 할당

로컬에서 쓰는 데이터베이스와 배포한 뒤에 사용하는 데이터베이스가 달라서
정확한 테스트를 위해 상용 데이터베이스를 로컬에서 진행할 수 있게 세팅 후에 문제를 찾았다.

로컬에서 잘 돌아갔던 이유는 A파일에 있는 데이터가 데이터베이스에 아무것도 없고,
배포 후에는 데이터베이스에 실제로 연결된 데이터가 많아서 오래걸린 것이다.
그 부분에 집중해서 문제를 확인했다.

실제로 쿼리가 잘 날아가는지 확인하기위해 console.log를 확인하니
1초에 10개 정도씩 날아가고 있었다.
Promise.all 을 적용해서 한꺼번에 날아가야 맞다.
그런데 쿼리를 한꺼번에 보내는 게 제한이 있는 듯 했다.

해결방법을 찾던 중에 데이터베이스 레코드마다 인덱스를 할당하는 건 어떠냐는 의견이 있었다.
내가 기본적으로 알고 있는 primeKey 얘기가 아니다.
보통 노트정리를 할 때 투명인덱스 스티커를 책갈피처럼 붙이고 키워드를 적어서 한번에 펼칠 수 있는 것과 같은 작업이었다.

이 작업은 데이터베이스 스키마를 수정해서 진행할 수 있었다. (동료분이 진행해 주셨다.)

결과
로컬에서 해당데이터가 있는 데이터베이스를 연결했을 때도 3~4초 가량 소모됐다 !!
배포한 후에도 3~4초로 됐다. 성공이었다 !!

🚴‍ 쿼리에 WHERE IN 적용

기능이 원활하게 작동을 했지만, 데이터베이스에 수천 개의 쿼리를 날리기 보다
WHERE IN을 사용해서 1번의 쿼리만 사용하자는 의견이 있었다.
WHERE IN은 조회하고 싶은 키워드를 모두 보내서 해당 데이터를 한꺼번에 가져올 수 있다.

해당 쿼리까지 적용해서 기능을 완료했다.

🚴‍ 후기

로컬에서 가짜 데이터가 담긴 데이터베이스로 테스트하는 것과
배포 후, 진짜 데이터베이스를 적용했을 때 기능차이가 심하다는 것을 깨달았다.
테스트를 위해 개발용 데이터베이스에 실질 데이터를 세팅해주셔서 동료분들께 너무 감사했다.

소요시간이 너무 커서 타임아웃이 되는 상황에서 단번에 3~4초로 줄인 순간 정말 짜릿했다.
나 혼자 고민했다면 떠오르지 못했을 방법이라고 생각한다.
열심히 지식들을 주워 담아서 나중에는 나도 다른사람에게 도움을 줄 수 있었으면 좋겠다.

profile
기록하는 백엔드 개발자

0개의 댓글