TALEND

[TALEND] 대용량 테이블 성능 개선

escaper101 2021. 4. 8. 12:36

이번 포스팅에서는 Data Migration 업무를 수행하면서 마주한 여러 케이스들 중 대용량 소스 테이블을 타겟 테이블에 이관할 때 발생하는 성능 저하 문제를 해결한 팁들을 공유하려고 한다. 보통 화면에서 자주 사용되는 데이터를 담고있는 테이블의 경우 그 데이터 건수가 많아지면 front 영역에서 해당 데이터를 로딩하는 시간이 오래걸린다. 내 경험 상 Data Migration 중 성능 개선 대상이 된 테이블은 화면에서 사용하는 데이터를 담고 있는 테이블보다는 로그 성 테이블, 배치로 쌓이는 테이블 등이었다. 이러한 테이블의 특징으로는 특별한 ETL cleansing rule이 적용되기 보다는 as-is와 to-be 구조를 동일하게 유지하는 경우가 많았다. 

 

우선 이관 성능을 개선하기 위해 작업을 다음의 세 영역 중 어떤 단계에서 bottleneck 현상이 발생하고 있는지 파악해야 한다. 

1. 소스 테이블에서 Data fetch

2. mapping

3. 타겟 테이블로 Data load 

 

앞서 말했듯이 대용량 테이블의 경우 데이터 특성 상 mapping rule에 특별한 내용을 적용해야하는 경우가 거의 없다. (적어도 나의 경우는 그랬다) 따라서 두번째 단계인 mapping 단계에서 성능 문제가 발생할 여지가 적었다. 

세번째, 데이터를 타겟 테이블로 load 하는 단계의 경우는 분명 성능에 영향을 줄 수 있지만 작업 상황에 따라 제어가 힘들 가능성이 크다. 보통 load에 시간이 오래걸리는 경우 해당 database 인스턴스에 과부화가 있거나 이관 대상 테이블을 다른 시스템에서 동시에 조작하고 있는 경우가 많다. Data Migration 작업을 수행할 때 타겟이 되는 DB와 테이블에 과부화를 줄이기 위해 작업 시간동인 타겟 시스템 조작을 삼가달라는 요청을 할 수 있는 상황도 있겠으나 많은 경우 운영되고 있는 시스템에 데이터가 추가 이관되어야 하는 경우가 있다. 이 경우는 세번째 단계인 load에서 발생하는 성능 저하 문제 개선이 어려움이 있을 수 있다. 이 문제는 migration 작업 자체의 문제가 아니기 때문에 성능 개선의 범위라고 보기 힘들다.

따라서 우리는 첫번째 단계인 data fetch 에 중점을 두고 성능 개선 방법을 알아보겠다. 

 

1. 인덱스 칼럼으로 데이터 조회하기 

첫번째 케이스는 인덱스가 설정되어 있는 칼럼을 적극 활용하여 소스 데이터를 빠르게 fetch 해오는 방법이다. 이 방법은 소스 테이블을 인덱스 칼럼을 통해 스캔하도록 동적 쿼리를 만드는 것이 핵심이다. 

인덱스로 조회 

위 케이스는 제품 및 카테고리 관련 데이블을 이관할 때 주로 사용한 방법이다. 어떤 비즈니스이던 판매 상품이 있으면 그 상위 개념인 상품 카테고리나 상품 라인 코드 등의 대, 중 분류로 상품을 분류하는 시스템을 가지고 있다. 이때, 이러한 테이블은 해당 대, 중분류 칼럼에 인덱스가 설정되어 있는 경우가 많다. 

 

제품 라인 코드

우선 예시로 들고 있는 products 테이블에는 상품을 구분하는 productLine 칼럼이 있고 해당 칼럼에 인덱스가 걸려있다. 실제 소스 테이블을 가져올 때 인덱스가 설정되어 있는 productLine 칼럼으로 데이터를 조회하기 위해 productLine 모든 데이터를 중복값없이 가져오는 쿼리를 위와 같이 작성한다. 

tFlowToIterate

tFlowToIterate 컴포넌트를 사용하면 반복문처럼 productLine 데이터 하나하나에 접근할 수 있다. 그리고 productLine 데이터를 동일한 이름을 가진 변수에 저장한다. 

추출쿼리 

이제 변수에 저장된 productLine 데이터를 사용하여 소스 데이터를 가져오는 동적 쿼리를 만들어준다. 이렇게 하면 인덱스가 설정된 productLine 칼럼으로 소스 데이터를 fetch해 오기 때문에 아무런 조건 없이 가져오는 경우 보다 향상된 데이터 fetch 속도를 기대할 수 있다. 

 

 

2. 날짜 조건으로 가져오기 

대용량 데이터를 보유한 데이블은 대부분 데이터 생성 일자 혹은 인터페이스 일자 등 날짜 칼럼을 기준으로 데이터를 관리한다. 우리는 반복문을 사용해 날짜 칼럼을 바탕으로 소스 데이터를 fetch 하는 쿼리를 만들어 볼 것이다. 우선 완성된 Job을 먼저 보자. 

성능 개선 Job 1 
첫번째 input 테이블 쿼리 

이 예시에서는 이관 대상인 대용량 소스 테이블의 데이터 중 orderDate 칼럼을 기준으로 Job을 만들었다. 소스 테이블의 orderDate 칼럼의 YEAR 부분의 최소값과 최대값을 구하는 쿼리를 작성하여 두 결과 값을 조회하는 쿼리를 작성한다. 

tFlowToIterate 

tFlowToInterate 컴포넌트를 사용하여 orderDate 의 최소 연도와 최대 연도를 각각 minYear과 maxYear라는 변수로 저장한다. 

 

tLoop 1

위에서 만든 변수를 tLoop 컴포넌트에서 사용한다. from 영역에는 minYear 변수를 to 영역에는 maxYear 변수를 넣어 minYear ~ maxYear까지 1씩 값이 증가하도록 반복문을 만들어준다. (2003 -> 2004 -> 2005... maxYear) 여기서 만들어진 변수 역시 추후 소스 테이블에서 데이터를 가져오는 쿼리에 사용될 것이다. 

 

tLoop2

두번째 tLoop를 살펴보자. 위 최종 완성된 Job을 보면 첫번째 tLoop와 두번째 tLoop를 iterate 라인으로 연결하였는데 이렇게 하면 중첩 반복문을 사용하는 것과 같다. 앞서 살펴본 첫번째 tLoop에서는 연도 값이 변경되고 두번째 tLoop에서는 day 즉, 일자 값을 변경해주고 있다. 1부터 365까지 1씩 값이 변경되도록 설정하였다. 

 

tJava 

이제 tJava에서 실제 Where 조건 쿼리를 만들어보자. tLoop1에서 연도 값을 가져오고 tLoop2에서 일자 값을 가져와 소스 데이터의 최소 연도에서 부터 최대 연도까지 모든 날짜에 해당하는 데이터를 가져오는 동적 쿼리를 만들었다. 이제 이 쿼리를 실제 소스 테이블의 데이터를 fetch 해오는 쿼리에 추가할 것이다. 

추출 쿼리 

tJava에서 만든 동적 쿼리 변수 dataQuery를 추출 쿼리에 이어 붙인다. 그리고 완성된 Job 그림처럼 소스 테이블을 이관 대상인 타겟 테이블에 이어붙이면 Job이 완성이 된다. (내 경우는 타겟 테이블이 아닌 Talend 자체 로그에 출력하는 tLogRow를 이어붙였다.) 테이블의 데이터 건수가 많으면 BETWEEN, >, < 등을 사용하여 날짜범위로 데이터를 구분하여 가져오는 것도 시간이 오래걸릴 수 있다. 하지만 이렇게 특정 날짜 하루에 해당하는 데이터를 가져오는 방식으로 쿼리를 생성하면 범위 스캔이 아니기 때문에 fetch 속도가 더 빨라진다. 이때, 해당 칼럼에 Index가 설정되어 있으면 속도는 더욱 빠를 것이다. 

 

3. subjob을 병렬 / 순차적으로 수행 

세번째 방법은 인덱스 칼럼이 없는 경우 사용한 방법이다. 두번째에 소개한 날짜로 쿼리 조각을 만드는 방식과 병렬로 Job을 수행하는 방식 둘 다 알아두면 상황에 맞게 적절할 방법을 사용할 수 있으므로 소개해보려 한다. 이 경우 소스 데이터를 날짜 등의 특정 기준으로 100,000 ~ 500,000 건 정도로 구분한 subjob을 여러개 만들어 한번에 병렬로 수행하는 방식으로 Job의 구조를 만들었다. 이 케이스에 대한 내용은 이전 포스팅에서 다룬 적이 있으니 참고하시길 바란다. 

2020.12.30 - [TALEND] - [TALEND] 병렬/순차적 프로그램 실행

 

[TALEND] 병렬/순차적 프로그램 실행

이번 포스팅에서는 하나의 Job을 여러개의 subjob으로 구분하여 병렬로 수행하는 방법과 여러 개의 job을 순차적으로 수행하는 방법을 알아보자. employee 데이터를 가진 employee 테이블의 데이터는 위

doneisbetterthanperfect.tistory.com

 

4. 반복문 병렬 수행 (parallel execution)

마지막 방법은 세번째와는 약간 다른 반복문 병렬 수행 방식이다. 세번째 케이스는 하나의 Job의 여러개의 subjob을 병렬로 실행하는 것이고 이번에 소개할 케이스는 반복문 자체를 병렬로 수행하는 방법이다. 첫번째 방식으로 소개한 인덱스 칼럼으로 소스 테이블을 조회하는 Job에 약간의 설정만 추가하면 된다. 

아래는 앞서 살펴본 첫번째 케이스를 수행하는 Job이다. 

tFlowToIterate로 수행되는 반복문이 병렬로 수행되도록 할 것이다. 우선 tFlorToIterate와 소스 테이블인 products 테이블을 연결하고 있는 Iterate 선을 더블 클릭하자. 

itarete 설정 

그리고 Component 창으로 가 Enable parallel execution 체크박스를 선택하면 동시에 병렬 수행할 숫자를 입력하는 칸이 표시된다. 이 예시에서는 4개를 동시에 수행하도록 설정하였다. 

 

parallel execution 실행 

이제 설정을 마치고 Job을 실행하면 위와 같이 동시에 4개의 parallel execution이 실행되는 것을 볼 수 있다. 경험상 이 방법은 속도가 매우 빠르지만 동시에 타겟 시스템의 과부화를 야기할 수 있으니 사용 시 주의해야 한다. 

 

Data Migration 업무를 수행하면서 마주한 성능 관련 이슈들은 위 네 개가지의 케이스로 개선할 수 있었다. 이렇게 대용량 데이터를 포함하고 있는 테이블의 성능 개선을 위한 몇가지 팁을 공유해보았다.