모범 사례: Delta Lake

이 문서에서는 Delta Lake를 사용할 때의 모범 사례를 설명합니다.

Databricks는 예측 최적화를 사용하는 것이 좋습니다. Delta Lake에 대한 예측 최적화를 참조하세요.

동일한 위치에서 테이블을 삭제하고 다시 만들 때는 항상 문을 사용해야 CREATE OR REPLACE TABLE 합니다. 델타 테이블 삭제 또는 바꾸기를 참조 하세요.

최적화된 데이터 건너뛰기용 liquid 클러스터링 사용

Databricks는 데이터 건너뛰기를 위해 데이터 레이아웃을 최적화하기 위해 분할, Z 순서 또는 기타 데이터 조직 전략 대신 액체 클러스터링 사용하는 것이 좋습니다. Delta 테이블에 Liquid 클러스터링 사용을 참조하세요.

압축 파일

예측 최적화는 Unity 카탈로그 관리 테이블에서 자동으로 실행 및 VACUUM 명령을 실행 OPTIMIZE 합니다. Delta Lake에 대한 예측 최적화를 참조하세요.

Databricks는 작은 파일을 압축하기 위해 OPTIMIZE 명령을 자주 실행하는 것이 좋습니다.

참고 항목

이 작업은 이전 파일을 제거하지 않습니다. 제거하려면 VACUUM 명령을 실행합니다.

테이블의 콘텐츠 또는 스키마 교체

경우에 따라 Delta 테이블을 교체해야 할 수도 있습니다. 예시:

  • 테이블의 데이터가 올바르지 않고 내용을 교체하려고 합니다.
  • 호환되지 않는 스키마 변경(예: 열 형식 변경)을 수행하기 위해 전체 테이블을 다시 작성하려고 합니다.

Delta 테이블의 전체 디렉터리를 삭제하고 동일한 경로에 새 테이블을 만들 수 있지만 다음과 같은 이유로 권장하지 않습니다.

  • 디렉터리를 삭제하는 것은 효율적이지 않습니다. 매우 큰 파일이 포함된 디렉터리는 삭제하는 데 몇 시간 또는 며칠이 걸릴 수 있습니다.
  • 삭제된 파일의 모든 콘텐츠가 손실됩니다. 잘못된 테이블을 삭제하면 복구하기가 어렵습니다.
  • 디렉터리 삭제는 원자성의 성격이 없습니다. 테이블을 삭제하는 동안 테이블을 읽는 동시 쿼리가 실패하거나 일부 테이블이 표시될 수 있습니다.

테이블 스키마를 변경할 필요가 없는 경우 Delta 테이블에서 데이터를 삭제하고 새 데이터를 삽입하거나 테이블을 업데이트하여 잘못된 값을 수정할 수 있습니다.

테이블 스키마를 변경하려는 경우 전체 테이블을 원자성으로 바꿀 수 있습니다. 예시:

Python

dataframe.write \
  .format("delta") \
  .mode("overwrite") \
  .option("overwriteSchema", "true") \
  .saveAsTable("<your-table>") # Managed table

dataframe.write \
  .format("delta") \
  .mode("overwrite") \
  .option("overwriteSchema", "true") \
  .option("path", "<your-table-path>") \
  .saveAsTable("<your-table>") # External table

SQL

REPLACE TABLE <your-table> USING DELTA AS SELECT ... -- Managed table
REPLACE TABLE <your-table> USING DELTA LOCATION "<your-table-path>" AS SELECT ... -- External table

Scala

dataframe.write
  .format("delta")
  .mode("overwrite")
  .option("overwriteSchema", "true")
  .saveAsTable("<your-table>") // Managed table

dataframe.write
  .format("delta")
  .mode("overwrite")
  .option("overwriteSchema", "true")
  .option("path", "<your-table-path>")
  .saveAsTable("<your-table>") // External table

이 방법에는 여러 가지 이점이 있습니다.

  • 테이블을 덮어쓰는 것은 디렉터리를 재귀적으로 나열하거나 파일을 삭제할 필요가 없기 때문에 훨씬 빠릅니다.
  • 이전 버전의 테이블이 여전히 존재합니다. 잘못된 테이블을 삭제하면 시간 여행을 사용하여 이전 데이터를 쉽게 검색할 수 있습니다. Delta Lake 테이블 기록 작업을 참조하세요.
  • 원자성 연산입니다. 테이블을 삭제하는 동안 동시 쿼리는 여전히 테이블을 읽을 수 있습니다.
  • Delta Lake ACID 트랜잭션 보장으로 인해 테이블 덮어쓰기가 실패하면 테이블은 이전 상태가 됩니다.

또한 테이블을 덮어쓰고 나면 스토리지 비용을 절약하기 위해 이전 파일을 삭제하려는 경우 VACUUM을 사용하여 삭제할 수 있습니다. 파일 삭제에 최적화되어 있으며 일반적으로 전체 디렉터리를 삭제하는 것보다 빠릅니다.

Spark 캐싱

Databricks는 다음과 같은 이유로 Spark 캐싱의 사용을 권장하지 않습니다.

  • 캐시된 DataFrame 위에 추가된 추가 필터로 인해 데이터 건너뛰기가 손실됩니다.
  • 다른 식별자를 사용하여 테이블에 액세스하는 경우 캐시되는 데이터가 업데이트되지 않을 수 있습니다.

Apache Spark에서 Delta Lake와 Parquet 간의 차이

Delta Lake는 다음 작업을 자동으로 처리합니다. 이러한 작업을 수동으로 수행해서는 안 됩니다.

  • REFRESH TABLE: 델타 테이블은 항상 최신 정보를 반환하므로 변경 후 REFRESH TABLE을 수동으로 호출할 필요가 없습니다.
  • 파티션 추가 및 제거: Delta Lake는 테이블에 있는 파티션 집합을 자동으로 추적하고 데이터가 추가되거나 제거되면 목록을 업데이트합니다. 따라서 실행 ALTER TABLE [ADD|DROP] PARTITION 또는 MSCK를 실행할 필요가 없습니다.
  • 단일 파티션 로드: 파티션을 직접 읽을 필요가 없습니다. 예를 들어 spark.read.format("parquet").load("/data/date=2017-01-01")를 실행할 필요가 없습니다. 대신 spark.read.table("<table-name>").where("date = '2017-01-01'")과 같이 데이터 건너뛰기를 위해 WHERE 절을 사용합니다.
  • 데이터 파일을 수동으로 수정하지 않음: Delta Lake는 트랜잭션 로그를 사용하여 변경 내용을 테이블에 원자 단위로 커밋합니다. 데이터 손실 또는 테이블 손상으로 이어질 수 있으므로 Delta 테이블에서 Parquet 데이터 파일을 직접 수정, 추가, 삭제하지 마세요.

Delta Lake 병합을 위한 성능 개선

다음 방법을 사용하여 병합하는 데 걸리는 시간을 줄일 수 있습니다.

  • 일치 항목의 검색 공간 줄이기: 기본적으로, merge 작업은 델타 테이블 전체를 검색하여 원본 테이블에서 일치 항목을 찾습니다. merge 작업의 속도를 높이는 한 가지 방법은 일치 조건에 알려진 제약 조건을 추가하여 검색 공간을 줄이는 것입니다. 예를 들어, countrydate로 분할된 테이블에서 merge를 사용하여 마지막 일자와 특정 국가에 대해 정보를 업데이트하려면 다음 조건을 추가하면 관련 파티션에서만 일치 항목을 찾기 때문에 쿼리가 더 빨라집니다.

    events.date = current_date() AND events.country = 'USA'
    

    또한 이 쿼리는 다른 동시 실행 작업과의 충돌 가능성도 줄입니다. 자세한 내용은 Azure Databricks의 격리 수준 및 쓰기 충돌을 참조하세요.

  • 압축 파일: 데이터가 여러 개의 작은 파일에 저장되어 있는 경우, 데이터를 읽어 들여 일치 항목을 검색하는 작업이 느려질 수 있습니다. 여러 개의 작은 파일을 큰 파일로 압축하면 읽기 처리량을 개선할 수 있습니다. 자세한 내용은 Delta Lake에서 최적화된 압축 데이터 파일을 참조하세요.

  • 쓰기를 위한 섞기 파티션 제어: merge 작업은 업데이트된 데이터를 계산하고 쓰기 위해 데이터를 여러 차례 섞습니다. 섞기에 사용되는 작업의 개수는 Spark 세션 구성 spark.sql.shuffle.partitions에 의해 제어됩니다. 이 매개 변수를 설정하면 병렬 처리를 제어하고 출력 파일의 개수를 정할 수 있습니다. 값을 늘리면 병렬 처리가 늘어나는 동시에 작은 데이터 파일의 개수도 늘어납니다.

  • 최적화된 쓰기 사용: 분할된 테이블의 경우 merge는 섞기 파티션의 개수보다 훨씬 많은 수의 작은 파일을 생성할 수 있습니다. 모든 섞기 작업은 여러 개의 파티션에 여러 개의 파일을 쓸 수 있어 성능 병목 상태의 원인이 될 수 있기 때문입니다. 최적화된 쓰기를 사용하도록 설정하여 파일 수를 줄일 수 있습니다. Azure Databricks의 Delta Lake에 대한 최적화된 쓰기를 참조 하세요.

  • 테이블의 파일 크기 조정: Azure Databricks는 델타 테이블에 파일을 다시 쓰는 작업이 자주 merge 발생하는지 자동으로 검색할 수 있으며 나중에 추가 파일 다시 쓰기를 예상하여 다시 작성된 파일의 크기를 줄일 수 있습니다. 자세한 내용은 파일 크기 튜닝을 참조하세요.

  • 낮은 순서 섞기 병합: 낮은 순서 섞기 병합 은 가장 일반적인 워크로드에 더 나은 성능을 제공하는 최적화된 구현 MERGE 을 제공합니다. 이에 더해, 수정되지 않은 데이터의 Z 순서 지정과 같은 기존 데이터 레이아웃 최적화도 유지합니다.

데이터 최신 상태 관리

각 쿼리 시작 시 델타 테이블은 자동으로 최신 버전의 테이블로 업데이트됩니다. 이 프로세스는 명령 상태에서 Updating the Delta table's state를 보고할 때 Notebook에서 관찰할 수 있습니다. 그러나 테이블에 대한 기록 분석을 실행하는 경우, 특히 스트리밍 데이터가 자주 수집되는 테이블의 경우 최신 데이터가 반드시 필요하지 않을 수 있습니다. 이러한 경우 델타 테이블의 부실 스냅샷에서 쿼리를 실행할 수 있습니다. 이 접근 방식은 쿼리에서 결과를 가져올 때 대기 시간을 줄일 수 있습니다.

Spark 세션 구성 spark.databricks.delta.stalenessLimit 을 시간 문자열 값(각각 1시간 또는 15m 15분)으로 1h 설정하여 부실 데이터에 대한 허용 오차를 구성할 수 있습니다. 이 구성은 세션에 따라 달라지며 테이블에 액세스하는 다른 클라이언트에는 영향을 주지 않습니다. 테이블 상태가 부실 한도 내에서 업데이트된 경우 테이블에 대한 쿼리는 최신 테이블 업데이트를 기다리지 않고 결과를 반환합니다. 이 설정은 테이블이 업데이트되는 것을 방지하지 않으며 부실 데이터가 반환되면 업데이트가 백그라운드에서 처리됩니다. 마지막 테이블 업데이트가 부실 한도보다 오래된 경우 쿼리는 테이블 상태 업데이트가 완료될 때까지 결과를 반환하지 않습니다.

대기 시간이 짧은 쿼리에 대한 향상된 검사점

Delta Lake는 최적화된 빈도에서 델타 테이블의 집계 상태로 검사점을 작성합니다. 이러한 검사점은 테이블의 최신 상태를 계산하기 위한 시작점 역할을 합니다. 검사점이 없으면 Delta Lake에서 테이블 상태를 계산하기 위해 트랜잭션 로그에 대한 커밋을 나타내는 대규모 JSON 파일("델타" 파일) 컬렉션을 읽어야 합니다. 또한 Delta Lake에서 데이터 건너뛰기를 수행하는 데 사용하는 열 수준 통계가 검사점에 저장됩니다.

Important

Delta Lake 검사점은 구조적 스트리밍 검사점과 다릅니다.

열 수준 통계는 구조체 및 JSON(이전 버전과의 호환성을 위해)으로 저장됩니다. 구조체 형식을 사용하면 다음과 같은 이유로 Delta Lake 읽기 속도가 훨씬 빨라집니다.

  • Delta Lake에서 열 수준 통계를 얻기 위해 비용이 많이 드는 JSON 구문 분석을 수행하지 않습니다.
  • Parquet 열 정리 기능에서 열에 대한 통계를 읽는 데 필요한 I/O를 크게 줄입니다.

구조체 형식을 사용하면 Delta Lake 읽기 작업의 오버헤드를 몇 초에서 수십 밀리초로 줄이는 최적화 컬렉션을 사용할 수 있으므로 짧은 쿼리의 대기 시간이 크게 줄어듭니다.

검사점에서 열 수준 통계 관리

delta.checkpoint.writeStatsAsJsondelta.checkpoint.writeStatsAsStruct 테이블 속성을 사용하여 검사점에서 통계가 작성되는 방법을 관리합니다. 두 테이블 속성이 모두 false인 경우 Delta Lake에서 데이터 건너뛰기를 수행할 수 없습니다.

  • 일괄 처리 쓰기에서 JSON 및 구조체 형식으로 통계를 작성합니다. delta.checkpoint.writeStatsAsJsontrue입니다.
  • delta.checkpoint.writeStatsAsStruct가 기본적으로 정의되지 않습니다.
  • 판독기에서 사용 가능한 경우 구조체 열을 사용하고, 그렇지 않으면 JSON 열을 사용하도록 대체합니다.

Important

향상된 검사점은 오픈 소스 Delta Lake 판독기와의 호환성을 손상시키지 않습니다. 그러나 delta.checkpoint.writeStatsAsJsonfalse로 설정하면 독점 Delta Lake 판독기에 영향을 줄 수 있습니다. 성능 영향에 대해 자세히 알아보려면 공급업체에 문의하세요.

구조적 스트리밍 쿼리에 향상된 검사점 사용

구조적 스트리밍 워크로드에 짧은 대기 시간 요구 사항(1분 미만의 대기 시간)이 없는 경우 다음 SQL 명령을 실행하여 향상된 검사점을 사용하도록 설정할 수 있습니다.

ALTER TABLE [<table-name>|delta.`<path-to-table>`] SET TBLPROPERTIES
('delta.checkpoint.writeStatsAsStruct' = 'true')

다음 테이블 속성을 설정하여 검사점 쓰기 대기 시간을 개선할 수도 있습니다.

ALTER TABLE [<table-name>|delta.`<path-to-table>`] SET TBLPROPERTIES
(
 'delta.checkpoint.writeStatsAsStruct' = 'true',
 'delta.checkpoint.writeStatsAsJson' = 'false'
)

애플리케이션에서 데이터 건너뛰기가 유용하지 않은 경우 두 속성을 모두 false로 설정할 수 있습니다. 그러면 통계가 수집되거나 기록되지 않습니다. Databricks는 이 구성을 권장하지 않습니다.