대부분 대용량 데이터 기준의 튜닝 포인트로 얘기하는 듯 함.
이것저것 많지만 개인적으로 숙지해야 될 것 위주로 적어 본다.
쓰잘데기 없다 싶은 것도 많은듯…
‘한 개의 큰 파일’을 자제하고, ‘한번에 작은 양의 파일’을 읽어야 한다.
athena는 다른 DB와 다르게 인덱스가 따로 존재하지 않고 partition key를 통해 인덱싱 하는 것으로 보인다.
partition은 일반적으로 파일을 나눠서 하는 경우가 많기도 하고… file을 직접 읽어 데이터를 추출하는 athena라면 파일 갯수를 병렬로 나누어 주는 것이 연산 상 이점이 충분할 것으로 보이긴 한다.
너무 많은 컬럼을 읽어오지 말 것. ( SELECT * 와 같은 )
일반 RDBMS또한 대용량을 다룬다면 동일한 튜닝포인트라고 볼 수 있다.
column 수를 줄이는 것이 더 적은 양의 데이터를 가져오고 join할 때도 덜 왔다갔다 한다는 뜻.
너무 많은 양의 데이터를 피할 것 & 전체 테이블 스캔을 피할 것
인덱스가 없다 보니 별 갖은 방법을…다 얘기하는 듯 하다. workaround로 CREATE TABLE AS SELECT ~ 구문을 추천하는 듯 함.(CTAS라나 뭐라나)
일반적으로 한 테이블에 많은 양의 데이터를 넣는 것이 부담스러우므로, scan 양을 줄이는 것이 지상 목표인 듯.
일반적인 쿼리 사용 주의점과 비슷한 레벨.
가능하다면 ‘너무 많은 양의 작은 파일’을 피할것.
위의 내용과 모순된다 싶어 좀 어이 없었는데 자세히 살펴 보니 그런 내용은 아니고, 아마존 S3와 아테나 모두 ‘초당 5500 리퀘스트’ 제한이 걸려 있다. 이걸 바꿀 수 있는 지는 모르겠으나…
작은 파일 단위로 수백만 개의 object를 쿼리로 조회한다고 했을 때, 이 초당 5500 리퀘스트 제한에 걸리게 되므로… 운이 나쁘다면 백만 개에 200초 정도가 걸릴 수도 있겠다.
If possible이 왜 나왔냐 하니, 일단은 AWS glue라는 서비스가 있긴 해서 이걸 통해 파일을 그룹핑하고 큰 파일처럼 다룰 수 있게 지원하는 것 같다.
https://aws.amazon.com/ko/premiumsupport/knowledge-center/glue-job-output-large-files/
https://docs.aws.amazon.com/glue/latest/dg/grouping-input-files.html
ETL도 있고 이것저것…
parquet이나 ORC 파일 사용하기.
parquet와 같은 column base 파일 포맷이 유리하다는 것
ORC : https://cwiki.apache.org/confluence/display/hive/languagemanual+orc
parquet : https://github.com/apache/parquet-format
대용량 데이터를 다룰 때 column-base의 이점은 상당히 크기 때문에 성능 차이가 꽤 날 것으로 생각되긴 한다.
parquet ↔ ORC 변경해보기
같은 데이터라도 해당 두 포맷이 큰 차이를 보일 수도 있다고 한다.
parquet는 압축에 강점을 보이니 중복성이 짙은 데이터는 효율성이 좋을 것이고, ORC는 일반 columnar의 특징을 가지고 있으니 해당 상황에 맞춰 사용하면 좋을 수 있겠다.
메모리를 많이 사용하는 쿼리 피하기
JOIN, GROUP BY, ORDER BY, UNION과 같은 쿼리들은 메모리에 많은 양의 데이터를 올려놓게 될 수도 있다.
aggregation 쿼리들은 다른 벤더에서도 많은 코스트를 유발하므로 아테나도 마찬가지인 듯
UNION ALL을 사용하기
UNION은 중복 제거 로직이 있고, UNION ALL은 중복 제거 로직이 없다.
당연히 중복 제거 로직이 없는 UNION ALL이 빠르다. 어차피 where절 등으로 원하는 row만 뽑기 때문에 일반적으로 UNION ALL을 사용하게 돼 있음.
파티션의 갯수에 제한을 두기
10만 개 이상 파티션이 존재할 경우 AWS에 과도한 리퀘스트를 날려 느려질 수 있다…
5500개의 제한 또한 문제가 될 수 있을 듯 한데, 정확하게 그렇게 적어놓진 않은 듯.
참고 : https://docs.aws.amazon.com/athena/latest/ug/partition-projection.html
partition projection이 뭔가 하니, 기존에는 파티션 정보를 가져올 때 GetPartitions API를 사용하는데 이게 상당한 부하를 유발할 수 있다고 한다. before pruning이라 하는 것을 보니, 인덱스 파편화 등의 문제로 부하가 걸릴 수 있는듯.
RDBMS에서 특정 컬럼만 가져오는 것 처럼, 파티션 또한 그렇게 작동할 수 있다~
ALTER TABLE ADD PARTITION을 사용할 것
파일을 추가하고 파티션을 추가하는 방법엔 두 가지가 있는데, 그 중 하나 얘기다.
적어 놓은 것으로도 알 수 있듯 전자는 모든 하위 디렉토리를 훑기 때문에 엄청난 시간이 걸릴 수 있다.
MSCK는 처음 테이블 생성 시 누락을 방지하기 위해 수행 해 주되, 주기적으로 데이터가 추가되는 파이프라이닝 상황에서는 ADD PARTITION을 애용한다.
WHERE절에 coalesce()를 사용하지 말 것
명확한 이유를 적어 놓진 않았으나… 굳이 coalesce에 한정되지 않고 function 대부분을 얘기하고 있긴 하다.
일반적으로 WHERE절에 함수가 들어갈 경우 성능 저하를 일으킬 수 있다. RDBMS index에서도 동일한 문제이고 아테나는 더할 수도 있겠다. 이럴 경우 workaround 쿼리(가능하다면)로 부하를 줄여 주는 것이 좋다.
window function을 최소하하기
rank와 같은 윈도우 함수들은 많은 메모리 사용을 유발한다. 집계 함수 대부분이 그런 식이기도 하나, 파티션에 대부분의 코스트를 의존하고 있는 아테나에겐 더 치명적일 수 있다.
엄청난 빅데이터 셋을 조회하게 될 경우 장애를 일으킬 수 있다.
좀 더 효율적인 함수 트릭 사용
여기에 좀 꿀팁이 있는 듯…
row_number를 이용한 rank 집계 함수 같은 느낌인데, 이것을 Group by , order by, limit 1 등을 이용해서 메모리에 올라가는 양을 줄이라는 것으로 보인다.
보통 RDBMS에서는 limit를 걸 경우 데이터셋을 딱 원하는 만큼만 fetch하기 때문에 상당한 속도 차이가 있는데, 이게 아테나에서도 적용되는진 의문이다. (실제로 아닌 경우도 있고)
어쨌거나 LIMIT를 권장할 정도면 속도 차이는 분명 있겠지. partition당 1 set만 가져온다거나..
LIKE ‘%string%’ 은 인덱싱이 제대로 존재하지 않는 아테나에선 치명적일 것이다.
b-tree index로 트리를 나눠 놓은 것도 아니고..필연적으로 거대한 데이터셋 스캔을 동반할 듯.
regexp_like() 함수가 있다고 하니 이걸 이용해서 하라고 한다.
참고 : https://prestodb.io/docs/current/functions/regexp.html#regexp_like
그 외에도 있으나 생략.
추가 문서 :
Top 10 Performance Tuning Tips for Amazon Athena | Amazon Web Services
이거 외에도 뭔가 팁이 있는 듯 한데, 다음에 정리할 게 있으면 또 하고…