데이터 최적화 - Amazon Athena

데이터 최적화

성능은 쿼리뿐만 아니라 데이터 세트의 구성 방식, 데이터 세트가 사용하는 파일 형식 및 압축에 따라 달라집니다.

데이터 파티셔닝

파티셔닝은 테이블을 여러 부분으로 나누고 날짜, 국가 또는 지역과 같은 속성을 기반으로 관련 데이터를 함께 보관합니다. 파티션 키는 가상 열 역할을 합니다. 테이블 생성 시 파티션 키를 정의하고 쿼리 필터링에 해당 파티션 키를 사용합니다. 파티션 키 열을 필터링하면 일치하는 파티션의 데이터만 읽습니다. 예를 들어 데이터 세트가 날짜별로 파티셔닝되어 있고 쿼리에 지난 주에만 일치하는 필터가 있는 경우 지난 주의 데이터만 읽습니다. 파티셔닝에 대한 자세한 내용은 데이터 파티셔닝 섹션을 참조하세요.

쿼리를 지원하는 파티션 키를 선택합니다.

파티셔닝은 쿼리 성능에 큰 영향을 미치므로 데이터 세트와 테이블을 설계할 때 파티셔닝을 신중하게 고려해야 합니다. 파티션 키가 너무 많으면 너무 작은 파일과 너무 많은 파일로 데이터 세트가 조각화될 수 있습니다. 반대로 파티션 키가 너무 적거나 전혀 파티셔닝하지 않으면 쿼리에서 필요 이상으로 많은 데이터를 스캔합니다.

드문 쿼리에 대한 최적화 방지

가장 일반적인 쿼리에 대해 최적화하고 드문 쿼리에 대해서는 최적화하지 않는 것이 좋습니다. 예를 들어 쿼리가 일 단위로 표시되는 경우 일부 쿼리가 해당 수준으로 필터링되더라도 시간 단위로 파티셔닝하지 않습니다. 데이터에 세밀한 수준의 타임스탬프 열이 있는 경우 시간 단위로 필터링하는 드문 쿼리에서 이 타임스탬프 열을 사용할 수 있습니다. 드물지만 필요 이상으로 데이터를 조금 더 많이 스캔하더라도 드문 상황에 대비해 전체 성능을 낮추는 작업은 일반적으로 좋은 절충안이 아닙니다.

쿼리에서 스캔해야 하는 데이터를 줄여 성능을 개선하려면 열 기반 파일 형식을 사용하고 레코드를 정렬된 상태로 유지합니다. 시간 단위로 파티셔닝하는 대신 타임스탬프를 기준으로 레코드를 정렬합니다. 기간이 짧은 쿼리의 경우 타임스탬프를 기준으로 정렬하는 방법이 시간 단위로 파티셔닝하는 것만큼 효율적입니다. 또한 타임스탬프를 기준으로 정렬해도 일반적으로 일 단위로 계산되는 기간에서는 쿼리 성능이 저하되지 않습니다. 자세한 내용은 열 기반 파일 형식 사용 단원을 참조하십시오.

수만 개의 파티션이 있는 테이블에 대한 쿼리의 경우 모든 파티션 키에 조건자가 있으면 성능이 개선됩니다. 가장 일반적인 쿼리에 대해 파티셔닝 체계를 설계해야 하는 또 다른 이유가 바로 여기에 있습니다. 자세한 내용은 관계 조건자로 파티션 쿼리 단원을 참조하십시오.

파티션 프로젝션 사용

파티션 프로젝션은 파티션 정보를 AWS Glue Data Catalog에 저장하지 않고 AWS Glue에서 테이블 속성의 규칙으로 저장하는 Athena 기능입니다. Athena에서 파티션 프로젝션으로 구성된 테이블에 대한 쿼리를 계획할 때 테이블의 파티션 프로젝션 규칙을 읽습니다. Athena에서는 AWS Glue Data Catalog에서 파티션을 조회하는 대신, 쿼리와 규칙을 기반으로 메모리에서 읽을 파티션을 계산합니다.

파티션 프로젝션은 파티션 관리를 단순화하는 것 외에도, 파티션 수가 많은 데이터 세트의 성능을 개선할 수 있습니다. 쿼리에 파티션 키의 특정 값 대신 범위가 포함된 경우 카탈로그에서 일치하는 파티션을 조회할 때 파티션이 많을수록 시간이 더 오래 걸립니다. 파티션 프로젝션을 사용하면 카탈로그로 이동하지 않고도 메모리에서 필터를 계산할 수 있으며 속도도 훨씬 더 빠를 수 있습니다.

경우에 따라 파티션 프로젝션으로 인해 성능이 저하되기도 합니다. 한 가지 예로 '스파스' 테이블이 이에 해당합니다. 스파스 테이블에는 파티션 프로젝션 구성에서 설명하는 파티션 키 값의 모든 순열에 대한 데이터가 포함되지 않습니다. 스파스 테이블을 사용하면 쿼리에서 계산된 파티션 세트와 파티션 프로젝션 구성은 데이터가 없어도 모두 Amazon S3에 나열됩니다.

파티션 프로젝션을 사용하는 경우 모든 파티션 키에 조건자를 포함해야 합니다. 불필요한 Amazon S3 나열을 피하려면 가능한 값의 범위를 좁힙니다. 값의 범위가 백만 개인 파티션 키와 해당 파티션 키에 필터가 없는 쿼리를 가정합니다. 쿼리를 실행하기 위해 Athena는 최소 백만 건의 Amazon S3 나열 작업을 수행해야 합니다. 파티션 프로젝션을 사용하든, 카탈로그에 파티션 정보를 저장하든 관계없이 특정 값을 쿼리할 때 쿼리 속도가 가장 빠릅니다. 자세한 내용은 관계 조건자로 파티션 쿼리 단원을 참조하십시오.

파티션 프로젝션에 대해 테이블을 구성하는 경우 지정하는 범위가 적절해야 합니다. 쿼리에서 파티션 키에 조건자가 포함되지 않는 경우 해당 키 범위의 모든 값이 사용됩니다. 데이터 세트가 특정 날짜에 생성된 경우 해당 날짜를 날짜 범위의 시작점으로 사용합니다. 종료 날짜 범위로는 NOW를 사용합니다. 값의 수가 많은 숫자 범위는 피하고 대신 injected 형식을 사용하는 것이 좋습니다.

파티션 프로젝션에 대한 자세한 내용은 Amazon Athena에서 파티션 프로젝션 사용 단원을 참조하세요.

파티션 인덱스 사용

파티션 인덱스는 파티션 수가 많은 테이블의 파티션 조회 성능을 개선하는 AWS Glue Data Catalog의 기능입니다.

카탈로그에서 파티션 목록은 관계형 데이터베이스의 테이블과 같습니다. 테이블에는 파티션 키에 해당하는 열과 파티션 위치에 해당하는 추가 열이 있습니다. 파티셔닝 테이블을 쿼리하는 경우 이 테이블을 스캔하면 파티션 위치를 조회합니다.

관계형 데이터베이스와 마찬가지로 인덱스를 추가하여 쿼리 성능을 높일 수 있습니다. 여러 인덱스를 추가하여 다양한 쿼리 패턴을 지원할 수 있습니다. AWS Glue Data Catalog 파티션 인덱스는 관계 연산자와 비교 연산자(예: >, >=, <)를 AND 연산자로 결합하여 모두 지원합니다. 자세한 내용은 AWS Glue 개발자 안내서Working with partition indexes in AWS GlueAWS 빅 데이터 블로그Improve Amazon Athena query performance using AWS Glue Data Catalog partition indexes를 참조하세요.

파티션 키 유형으로 항상 STRING 사용

파티션 키에서 쿼리하는 경우 파티션 필터링을 AWS Glue로 푸시다운하려면 Athena에 STRING 유형의 파티션 키가 필요합니다. 파티션 수가 적지 않은 경우 다른 유형을 사용하면 성능이 저하될 수 있습니다. 파티션 키 값이 날짜나 숫자와 비슷한 경우 쿼리에서 적절한 유형으로 변환합니다.

오래되고 비어 있는 파티션 제거

Amazon S3의 파티션에서 데이터를 제거하는 경우(예: Amazon S3 수명 주기 사용) AWS Glue Data Catalog에서도 파티션 항목을 제거해야 합니다. 쿼리 계획 중에 쿼리와 일치하는 모든 파티션이 Amazon S3에 나열됩니다. 빈 파티션이 많은 경우 이러한 파티션을 나열하며 발생하는 오버헤드로 인해 성능이 저하될 수 있습니다.

또한 수천 개의 파티션이 있는 경우 더 이상 관련이 없는 오래된 데이터에 대한 파티션 메타데이터를 제거하는 것이 좋습니다. 예를 들어 쿼리에서 1년이 넘은 데이터를 확인하지 않는 경우 오래된 파티션에 대한 파티션 메타데이터를 주기적으로 제거할 수 있습니다. 파티션 수가 수만 개로 늘어나는 경우 사용하지 않는 파티션을 제거하면 모든 파티션 키에서 조건자를 포함하지 않는 쿼리의 속도를 높일 수 있습니다. 쿼리에서 모든 파티션 키에 조건자를 포함하는 방법에 대한 자세한 내용은 관계 조건자로 파티션 쿼리 섹션을 참조하세요

관계 조건자로 파티션 쿼리

모든 파티션 키에서 관계 조건자를 포함하는 쿼리는 파티션 메타데이터를 직접 로드할 수 있으므로 실행 속도가 더 빠릅니다. 하나 이상의 파티션 키에 조건자가 없거나 조건자에서 값 범위를 선택하는 쿼리는 피합니다. 이러한 쿼리의 경우 일치하는 값을 찾으려면 모든 파티션 목록을 필터링해야 합니다. 대부분의 테이블에서 이러한 오버헤드가 최소한의 수준이지만, 파티션이 수만 개가 넘는 테이블의 경우 이러한 오버헤드는 심각해질 수 있습니다.

쿼리를 다시 작성하여 파티션을 관계 조건자로 필터링할 수 없는 경우 파티션 프로젝션을 시도할 수 있습니다. 자세한 내용은 파티션 프로젝션 사용 단원을 참조하십시오.

파티션 유지 관리에 MSCK REPAIR TABLE 사용 방지

MSCK REPAIR TABLE은 실행 시간이 오래 걸릴 수 있으며 새 파티션만 추가하고 오래된 파티션은 제거하지 않으므로 파티션을 효율적으로 관리할 수 있는 방법이 아닙니다(고려 사항 및 제한 참조)

파티션은 AWS Glue Data Catalog API, ALTER TABLE ADD PARTITION 또는 AWS Glue 크롤러를 사용하여 수동으로 관리하는 것이 보다 효율적입니다. 다른 방법으로, 파티션 프로젝션을 사용할 수도 있습니다. 그러면 파티션을 모두 관리할 필요가 없습니다. 자세한 내용은 Amazon Athena에서 파티션 프로젝션 사용 단원을 참조하십시오.

쿼리가 파티셔닝 체계와 호환되는지 확인

EXPLAIN 문을 사용하여 쿼리에서 스캔할 파티션을 미리 확인할 수 있습니다. 쿼리 앞에 EXPLAIN 키워드를 접두사로 추가하고 각 테이블의 Fragment 2 [SOURCE] 출력 하단 근처에서 소스 조각(예:EXPLAIN)를 조회합니다. 오른쪽이 파티션 키로 정의된 할당을 조회합니다. 아래 줄에는 쿼리가 실행될 때 스캔할 해당 파티션 키의 모든 값 목록이 포함되어 있습니다.

예를 들어 dt 파티션 키가 있는 테이블에 쿼리가 있고 이 쿼리에 EXPLAIN 접두사를 추가한다고 가정합니다. 쿼리의 값이 날짜이고 필터로 3일 범위를 선택하는 경우 EXPLAIN 출력은 다음과 비슷합니다.

dt := dt:string:PARTITION_KEY :: [[2023-06-11], [2023-06-12], [2023-06-13]]

EXPLAIN 출력에서는 플래너가 이 파티션 키에 대해 쿼리와 일치하는 세 개의 값을 찾았음을 보여줍니다. 또한 해당 값도 표시합니다. EXPLAIN 사용에 대한 자세한 내용은 Athena에서 EXPLAIN 및 EXPLAIN ANALYZE 사용Athena EXPLAIN 문 결과 이해 섹션을 참조하세요.

열 기반 파일 형식 사용

Parquet 및 ORC와 같은 열 기반 파일 형식은 분산 분석 워크로드를 위해 설계되었습니다. 이 파일 형식에서는 데이터를 행 대신 열을 기준으로 구성합니다. 데이터를 열 형식으로 구성하면 다음과 같은 이점이 있습니다.

  • 쿼리에 필요한 열만 로드됨

  • 로드해야 하는 전체 데이터 양이 감소함

  • 열 값이 함께 저장되므로 데이터를 효율적으로 압축할 수 있음

  • 엔진에서 불필요한 데이터를 로드하지 않고 건너뛸 수 있도록 하는 메타데이터가 파일에 포함될 수 있음

파일 메타데이터를 사용하는 방법의 예로, 파일 메타데이터에서 데이터 페이지에 최솟값 및 최댓값에 대한 정보가 포함될 수 있습니다. 쿼리된 값이 메타데이터에 명시된 범위를 벗어나면 페이지를 건너뛸 수 있습니다.

이 메타데이터를 사용하여 성능을 향개선하는 한 가지 방법은 파일 내의 데이터를 정렬하는 것입니다. 예를 들어 created_at 항목이 짧은 기간에 포함된 레코드를 찾는 쿼리를 가정합니다. 데이터가 created_at 열을 기준으로 정렬된 경우 Athena는 파일 메타데이터의 최솟값과 최댓값을 사용하여 데이터 파일의 불필요한 부분을 건너뛸 수 있습니다.

열 기반 파일 형식을 사용하는 경우 파일 크기가 너무 작지 않아야 합니다. 너무 많은 수의 파일 방지에서 설명한 것처럼 작은 파일이 많은 데이터 세트는 성능 문제를 일으킬 수 있습니다. 열 기반 파일 형식에서 특히 그렇습니다. 크기가 작은 파일의 경우 열 기반 파일 형식에서 오버헤드의 단점이 장점보다 더 큽니다.

Parquet 및 ORC는 내부적으로 행 그룹(Parquet) 및 스트라이프(ORC)로 구성됩니다. 행 그룹의 기본 크기는 128MB이고 스트라이프의 경우 64MB입니다. 열이 많은 경우 더 나은 성능을 위해 행 그룹과 스트라이프 크기를 늘릴 수 있습니다. 행 그룹 또는 스트라이프 크기를 기본값보다 작게 줄이는 것은 권장되지 않습니다.

다른 데이터 형식을 Parquet 또는 ORC로 변환하기 위해 AWS Glue ETL 또는 Athena를 사용할 수 있습니다. 자세한 내용은 열 기반 형식으로 변환 단원을 참조하십시오.

데이터 압축

Athena에서는 다양한 압축 형식을 지원합니다. 압축을 해제하기 전에 스캔한 바이트 수만큼 비용이 청구되므로 압축된 데이터를 쿼리하는 것이 더 빠르고 비용도 저렴합니다.

gzip 형식은 뛰어난 압축률을 제공하며 다른 여러 도구 및 서비스에서 폭넓게 지원됩니다. zstd(Zstandard) 형식은 성능과 압축률 간 균형이 잘 잡힌 최신 압축 형식입니다.

JSON 및 CSV 데이터와 같은 텍스트 파일을 압축할 때는 파일 수와 파일 크기 사이의 균형을 맞춥니다. 대부분의 압축 형식을 사용하려면 처음부터 리더에서 파일을 읽어야 합니다. 즉, 압축된 텍스트 파일은 일반적으로 병렬로 처리할 수 없습니다. 압축되지 않은 큰 파일은 쿼리 처리 중에 병렬 처리 성능을 높이기 위해 종종 작업자 사이에서 분할되기도 하지만, 대부분의 압축 형식에서는 지원되지 않습니다.

너무 많은 수의 파일 방지에서 설명한 것처럼 파일이 너무 많거나 너무 적지 않은 것이 좋습니다. 파일 수는 쿼리를 처리할 수 있는 작업자 수의 한도이므로 이 규칙은 특히 압축된 파일에 적용됩니다.

Athena에서 압축 사용에 대한 자세한 내용은 Athena에서 압축 사용 섹션을 참조하세요.

카디널리티가 높은 키에서 조회할 때 버킷팅 사용

버킷팅은 열 중 하나의 값을 기준으로 레코드를 별도의 파일로 분산하는 기법입니다. 이렇게 하면 값이 같은 모든 레코드가 같은 파일에 보관됩니다. 버킷팅은 카디널리티가 높은 키가 있고 많은 쿼리에서 해당 키의 특정 값을 조회하는 경우에 유용합니다.

예를 들어 특정 사용자에 대한 레코드 세트를 쿼리한다고 가정합니다. 데이터가 사용자 ID로 버킷팅되는 경우 Athena는 특정 ID에 대한 레코드를 포함하는 파일과 그렇지 않은 파일을 미리 파악합니다. 이를 통해 Athena가 ID를 포함할 수 있는 파일만 읽을 수 있으므로 읽는 데이터의 양이 크게 줄어듭니다. 또한 특정 ID를 찾기 위해 데이터를 검색하는 데 필요한 컴퓨팅 시간도 줄어듭니다.

쿼리에서 열의 여러 값을 자주 검색하는 경우 버킷팅 방지

쿼리에서 데이터가 버킷팅되는 열의 여러 값을 자주 검색하는 경우에는 버킷팅의 효율성이 떨어집니다. 쿼리되는 값이 많을수록 전체 또는 대부분의 파일을 읽어야 할 가능성이 커집니다. 예를 들어 버킷이 3개이고 쿼리에서 세 개의 다른 값을 조회하는 경우 모든 파일을 읽어야 할 수 있습니다. 버킷팅은 쿼리에서 단일 값을 조회할 때 가장 효과적입니다.

자세한 내용은 분할 및 버킷팅 사용 단원을 참조하십시오.

너무 많은 수의 파일 방지

많은 수의 작은 파일로 구성된 데이터 세트는 전체 쿼리 성능을 저하시킵니다. Athena는 쿼리를 계획할 때 모든 파티션 위치를 나열하므로 시간이 걸립니다. 각 파일을 처리하고 요청하는 데에도 계산 오버헤드가 발생합니다. 따라서 Amazon S3에서 큰 파일 하나를 로드하는 것이 많은 수의 작은 파일에서 동일한 레코드를 로드하는 것보다 빠릅니다.

극단적인 경우에는 Amazon S3 서비스 한도에 도달할 수 있습니다. Amazon S3는 단일 인덱스 파티션에 대해 초당 최대 5,500개의 요청을 지원합니다. 처음에는 버킷을 단일 인덱스 파티션으로 취급하지만 요청 로드가 증가하면 여러 인덱스 파티션으로 분할할 수 있습니다.

Amazon S3는 요청 패턴을 확인하고 키 접두사를 기반으로 분할합니다. 데이터 세트가 수천 개의 파일로 구성된 경우 Athena에서 수신되는 요청이 요청 할당량을 초과할 수 있습니다. 파일 수가 적더라도 동일한 데이터 세트에 대해 여러 개의 동시 쿼리를 수행하면 할당량을 초과할 수 있습니다. 동일한 파일에 액세스하는 다른 애플리케이션이 총 요청 수에 영향을 미칠 수도 있습니다.

요청 속도(limit)를 초과하면 Amazon S3는 다음 오류를 반환합니다. 이 오류는 Athena에서 쿼리 상태 정보에 포함됩니다.

SlowDown: Please reduce your request rate

문제를 해결하려면 먼저 오류가 단일 쿼리에서 발생했는지, 아니면 동일한 파일을 읽는 여러 쿼리에서 발생했는지 확인합니다. 후자인 경우 쿼리가 동시에 실행되지 않도록 쿼리 실행을 조정합니다. 이를 위해 애플리케이션에 대기열 메커니즘을 추가하거나 재시도를 추가합니다.

단일 쿼리를 실행할 때 오류가 발생하는 경우 데이터 파일을 결합하거나 읽는 파일 수를 줄이도록 쿼리를 수정합니다. 작은 파일을 결합하기에 가장 좋은 시점은 파일을 쓰기 전입니다. 이를 위해 다음 기법을 고려합니다.

파티션 이외의 추가 스토리지 계층 구조 방지

쿼리 계획 오버헤드를 방지하려면 각 파티션 위치에 파일을 플랫 구조로 저장합니다. 추가 디렉터리 계층 구조는 사용하지 않습니다.

Athena는 쿼리를 계획할 때 쿼리와 일치하는 모든 파티션의 모든 파일을 나열합니다. Amazon S3에 디렉터리 자체는 없지만, / 슬래시를 디렉터리 구분 기호로 해석하는 것이 규칙입니다. Athena는 파티션 위치를 나열할 때 찾은 모든 디렉터리를 반복적으로 나열합니다. 파티션 내 파일을 계층 구조로 구성하면 여러 차례 나열이 수행됩니다.

모든 파일이 파티션 위치에 바로 있으면 대부분의 경우 한 번의 나열 작업만 수행하면 됩니다. 그러나 Amazon S3는 나열 작업당 1,000개의 객체만 반환하므로 파티션에 1,000개가 넘는 파일이 있으면 순차 나열 작업이 여러 차례 필요합니다. 파티션에 1,000개가 넘는 파일이 있으면 더 심각한 다른 성능 문제가 발생할 수도 있습니다. 자세한 내용은 너무 많은 수의 파일 방지 단원을 참조하십시오.

필요한 경우에만 SymlinkTextInputFormat 사용

SymlinkTextInputFormat 기법을 사용하면 테이블의 파일이 파티션으로 깔끔하게 구성되지 않은 상황을 해결할 수 있습니다. 예를 들어 모든 파일에서 접두사가 같거나 스키마가 다른 파일이 같은 위치에 있는 경우 symlink가 유용할 수 있습니다.

하지만 symlink를 사용하면 쿼리 실행이 더 간접적으로 이루어집니다. 이렇게 간접적으로 이루어진 쿼리 실행은 전체 성능에 영향을 미칩니다. symlink 파일을 읽고 symlink 파일이 정의한 위치를 나열해야 합니다. 이로 인해 일반적인 Hive 테이블에서는 필요하지 않은 여러 번의 왕복 작업이 Amazon S3에 추가됩니다. 결론적으로, 파일 재구성과 같은 더 나은 옵션을 사용할 수 없는 경우에만 SymlinkTextInputFormat을 사용해야 합니다.