반응형

react datatable (https://github.com/gregnb/mui-datatables)

사내에서 react-datatable를 브라우저 테이블으로 사용하고 있는데

렌더링 성능 이슈로 40~50만 건의 row 데이터 처리가 불가능해서 아예 테이블을 자체 구현하라는 지시가 떨어졌다.

이 글은 고분군투하면서 그 과정을 기록한 눈물겨운 글이다..

 

요구 스펙

 

1. 최소 column 10개, 100만 row를 브라우저에 렌더링 가능할 것 

*맨 처음 렌더링 성능 이슈를 해결하기 위해서 서버 페이지네이션을 생각하고 있었는데

이 요구사항으로 인해 최소 100만개는 클라이언트에 렌더링 되도록 구현해야 했다.

 

+ 가상화 라이브러리 (react-virtualized등) 적용

 

2. 현존하는 테이블 라이브러리보다 성능이 좋거나 대등할것 (!?)

특히, 1번 케이스에서 다른 테이블 라이브러리처럼 초기 렌더링이 3~5초 이내여야 한다.

 

3. 기존 테이블 라이브러리의 기능을 모두 갖출 것 (sorting, searching, filtering, pagination, inifinity scroll 등)

 

처음엔 tanstack table headless 라이브러리를 사용하려고 했는데 

메모리 사용량이 1번 스펙을 충족하지 못해서 할 수 없이 데이터구조도 자체구현 하는쪽으로 하기로 결정했다.

 

(tanstack table은 메모라이징 및 각종 지표를 제공하면서 메모리를 과다 사용해서

13개 column, 50만 row가 주어질때 다른 테이블이 200MB를 쓴다면,

tanstack table은 1.6 GB를 사용해서 대용량 처리엔 알맞지 않다는 결론을 내림)

 

초기 데이터 구조

sql select문 순서!

DB의 Select문에서 영감을 받아서 설계했는데 

원본 데이터 → ( execution ) → 현재 필요한 데이터만 UI에 전달하는 식으로 구현했다.

초기 데이터 구조 예시

UI 데이터의 관계를 분리했다.

 

원본 데이터 상태(originalData)가 있고,

sortingState, filteringState, paginationState 등등 여러 조건들을 상태로 observing하여

상태가 바뀔때마다 필터링해서 현재 UI에 필요한 데이터만 전달한다. 

 

즉, 각 sorting, filtering 상태는 Finite State Machine처럼 어떤 특정 상태를 가지고 있고, 그 상태에 맞추어서

originalData를 필터링해 최종적으로 UI에서 현재 원하는 데이터만 필터링해서 볼 수 있다.

 

더보기

* 초기 데이터 구조라고 써놨는데 

sorting, search같이 반드시 모든 데이터를 한번 순회 해야하는 경우도 있을 것이고

화면에 현재 보이는 row들에게만 적용해야하는 경우도 있을 것이다.

 

그래서 실 코드 구현 예시는

가상화 라이브러리를 이용해서 lazy하게 적용되는 파트와

위 예시처럼 한번 모든 row를 순회하며 적용하는 2가지 케이스로 나뉘어져 있다.

 

 

코드 예시

위 설계 부분을 그대로 코드로 구현한 것이다.

 

예시 코드이고 실제 구현된 코드와는 다름

*flow는 함수형 프로그래밍의 pipe 함수(관련 링크)이며, lodash에 구현되어 있다.

 

예시 코드에 있는 id를 +1 하는 의미없는 함수들은 성능을 측정하기 위해 집어넣은 sorting, filtering, pagination등의 mocking 구현체를 뜻한다. 

 

테이블 UI 예시

 

Body

블로그에 올리기 위한 예시 코드이고 실제 구현된 코드와는 다름

필터링된 최종 결과물을 화면에 렌더링한다.

sorting 되었다면 visibleRowData는 오름차순으로 정렬되어 제공될 것이다.

특정 열이 숨김 처리되었다면 visibleRowData는 특정 행들이 제거되어 제공될 것이다.

 

UI 입장에서는 데이터를 가공하는 중간 과정을 알 필요가 없이 자신이 요청한 데이터를 그대로 쓸 수 있다.

 

코드 예시에는 가상화 라이브러리가 적용되어 있지 않는데, 

120만개의 row가 테이블에 제공된다면 row 모두를 dom에 그릴 필요는 없을 것이니

보이는 부분만 렌더링 시키는 가상화 라이브러리를 적용하면 된다. 

 

테이블 header 예시 

블로그에 올리기 위한 예시 코드이고 실제 구현된 코드와는 다름

handleSort로 sortingState 상태를 변경한다. 

그럼 rowData들이 sorting되어 body에 보여지게 된다.

 

구현 결과

현존하는 tanstack table, tui-grid, mui datatable등과 비교해봤는데 직접적인 수치를 제공할 수는 없지만

초기 요구사항을 모두 만족했고 대등하거나 더 나은 성능을 보여줬다.

 

특히, 메모리 부분에 신경써서 10개의 column, 1000만 row까지는 무리없이 몇초내에 렌더링하는 성능을 보여줬다.

다만 1000만개정도 무지막지한 데이터양이라면 row를 브라우저에 가져오지 않고 서버 페이지네이션을 구현하는 절충안으로 나아갈 것이다..

 

반응형

+ Recent posts