본 글은 Delta Lake 2.2.0 Best practices 을 번역 및 정리하였습니다.
이 문서에서는 Delta Lake 사용 시 최선의 방법에 대해 설명합니다.
Delta Lake 테이블을 열로 분할 할 수 있습니다. 가장 일반적으로 사용되는 분할 열은 날짜입니다. 분할할 열을 결정할 때 다음 두 가지 규칙을 따르세요.
Delta 테이블에 지속적으로 데이터를 기록하면 시간이 지남에 따라 많은 수의 파일이 누적됩니다. 특히 작은 batch 단위로 데이터를 추가하는 경우에는 더 그러합니다. 이렇게 되면 테이블 읽기의 효율에 부정적인 영향을 미치며 파일 시스템의 성능에도 영향을 미칠 수 있습니다. 이상적으로는 많은 수의 작은 파일을 정기적으로 더 적은 수의 큰 파일로 다시 작성해야 합니다. 이를 컴팩션이라고 합니다.
테이블을 재파티셔닝하여 더 작은 수의 파일로 압축할 수 있습니다. 또한 데이터가 변경되지 않고 데이터 레이아웃만 재배치되기 때문에 다른 동시 작업에 최소한의 영향을 미치도록 옵션 dataChange을 false로 지정할 수 있습니다.
예를 들어, 테이블을 16개 파일로 압축할 수 있습니다.
path = "..."
numFiles = 16
(spark.read
.format("delta")
.load(path)
.repartition(numFiles)
.write
.option("dataChange", "false")
.format("delta")
.mode("overwrite")
.save(path))
테이블이 파티션화되어 있고, 조건에 따라 하나의 파티션만 재분할하려는 경우, WHERE을 사용하여 해당 파티션만 읽은 후 replaceWhere를 사용하여 다시 작성할 수 있습니다.
path = "..."
partition = "year = '2019'"
numFilesPerPartition = 16
(spark.read
.format("delta")
.load(path)
.where(partition)
.repartition(numFilesPerPartition)
.write
.option("dataChange", "false")
.format("delta")
.mode("overwrite")
.option("replaceWhere", partition)
.save(path))
💡 경고
데이터를 변경하는 작업에서 dataChange = false를 사용하면 테이블의 데이터가 손상될 수 있습니다.
💡 참고이 작업은 이전 파일을 제거하지 않습니다. 이전 파일을 제거하려면 VACUUM 명령을 실행하십시오.
Delta 테이블을 대체하려는 경우가 있습니다. 예를 들어,
Delta 테이블의 전체 디렉토리를 삭제하고 동일한 경로에 새 테이블을 만들 수는 있지만 권장되지 않습니다. 이유는 다음과 같습니다:
테이블 스키마를 변경하지 않아도 된다면 Delta 테이블에서 데이터를 삭제하고 새 데이터를 삽입하거나, 잘못된 값을 수정하기 위해 테이블을 업데이트할 수 있습니다.
테이블 스키마를 변경하려면 전체 테이블을 원자적으로 교체할 수 있습니다. 예를 들어:
REPLACETABLE <your-table>USING DELTA PARTITIONEDBY (<your-partition-columns>)ASSELECT ... -- Managed table
REPLACETABLE <your-table>USING DELTA PARTITIONEDBY (<your-partition-columns>)LOCATION "<your-table-path>"ASSELECT ... -- External table
dataframe.write \
.format("delta") \
.mode("overwrite") \
.option("overwriteSchema", "true") \
.partitionBy(<your-partition-columns>) \
.saveAsTable("<your-table>") # Managed table
dataframe.write \
.format("delta") \
.mode("overwrite") \
.option("overwriteSchema", "true") \
.option("path", "<your-table-path>") \
.partitionBy(<your-partition-columns>) \
.saveAsTable("<your-table>") # External table
이 방법의 여러 가지 이점이 있습니다.
Delta Lake ACID 트랜잭션 보장으로 인해 테이블 덮어쓰기가 실패하면 테이블은 이전 상태로 유지됩니다.
또한, 테이블을 덮어쓴 후 저장소 비용을 절약하려면 VACUUM을 사용하여 이전 파일을 삭제할 수 있습니다. 파일 삭제를 최적화하고 일반적으로 디렉토리 전체를 삭제하는 것보다 빠릅니다.
Databricks는 다음 이유로 Spark 캐싱 사용을 권장하지 않습니다:
spark.table(x).cache()
를 수행하지만, spark.write.save(/some/path)
를 사용하여 테이블을 쓰는 경우)