---
title: Notebook에서 Lakehouse 테이블로 저장하기: saveAsTable과 mode의 의미
description: write.format(delta).saveAsTable()의 overwrite/append 차이부터 스키마가 바뀌었을 때 쓰는 mergeSchema·overwriteSchema까지 실무 예제로 정리했어요.
date: 2026-09-24
  tags: [Notebook, Delta, saveAsTable, PySpark, Lakehouse]
cards:
  - /cards/fabric-notebook-write-delta-table/card-01.png
  - /cards/fabric-notebook-write-delta-table/card-02.png
  - /cards/fabric-notebook-write-delta-table/card-03.png
  - /cards/fabric-notebook-write-delta-table/card-04.png
  - /cards/fabric-notebook-write-delta-table/card-05.png
  - /cards/fabric-notebook-write-delta-table/card-06.png
  - /cards/fabric-notebook-write-delta-table/card-07.png
author: Lissa
source: https://interlinear.work/notes/fabric-notebook-write-delta-table/
---

> **원문:** [Schema evolution for Delta tables](https://learn.microsoft.com/en-us/fabric/data-engineering/delta-lake-schema-evolution)
> **게시일:** 2026-05-18

Notebook에서 데이터를 이리저리 다듬고 나면 결국 궁금해지는 건 하나예요. "이걸 이제 Lakehouse 테이블로 저장하려면?" 답은 `saveAsTable()`인데, 뒤에 붙는 `mode`와 옵션들의 의미를 모르고 쓰면 기존 데이터를 통째로 날리거나, 반대로 스키마가 바뀐 데이터를 계속 튕겨내는 에러를 만나게 돼요.

## 기본형: write, format, saveAsTable

DataFrame을 Delta 테이블로 저장하는 기본 문법은 이래요.

```python
df.write.mode("overwrite").format("delta").saveAsTable("sales")
```

`format("delta")`는 저장 형식을 Delta Lake로 지정하는 부분이고, `saveAsTable("sales")`는 그 결과를 Lakehouse의 **Tables** 영역에 `sales`라는 이름의 테이블로 등록하는 부분이에요. 여기까지는 새 테이블을 만들 때나 기존 테이블을 완전히 새 데이터로 바꿀 때나 똑같이 씁니다.

## overwrite와 append, 헷갈리면 안 되는 부분

`mode`는 이미 같은 이름의 테이블이 있을 때 어떻게 할지를 정해요.

- **overwrite**: 기존 테이블 데이터를 지우고 새 DataFrame 내용으로 완전히 바꿔요.
- **append**: 기존 데이터는 그대로 두고, 새 DataFrame 내용을 뒤에 누적해서 추가해요.

```python
# 기존 데이터를 새 결과로 통째로 교체
df.write.mode("overwrite").format("delta").saveAsTable("sales")

# 기존 데이터에 새로 들어온 데이터를 누적
df.write.mode("append").format("delta").saveAsTable("sales")
```

매일 실행되는 배치 작업이라면, 그날 처리한 결과를 통째로 다시 쓰는 건지(overwrite), 그날 새로 생긴 데이터만 얹는 건지(append)를 먼저 정하고 코드를 짜야 해요. 이 둘을 헷갈리면 "테이블이 매번 리셋되는데요"나 "같은 데이터가 계속 중복돼요" 같은 문제로 바로 이어져요.

## 파티션을 나눠서 저장하기

큰 테이블은 자주 조회하는 컬럼(날짜 등) 기준으로 파티션을 나눠두면 이후 조회 성능에 도움이 돼요. DataFrameWriter의 `partitionBy()`를 `saveAsTable()` 앞에 붙이면 돼요.

```python
df.write.mode("overwrite").format("delta").partitionBy("OrderYear").saveAsTable("sales")
```

이렇게 하면 Delta 테이블 내부적으로 `OrderYear` 값별로 파일이 나뉘어 저장돼요. 다만 파티션 기준 컬럼은 나중에 바꾸기 까다로우므로, 카디널리티가 너무 높은 컬럼(예: 고유 ID)은 피하고 연·월처럼 값의 종류가 적당히 적은 컬럼을 고르는 게 안전해요.

## 스키마가 바뀌었을 때 — mergeSchema

운영 중인 테이블에 소스 쪽에서 새 컬럼이 추가되는 일은 흔해요. 기본적으로 Delta는 **쓰기 시점에 스키마를 강제**해요. 저장하려는 DataFrame이 테이블의 기존 스키마와 안 맞으면, 자동으로 맞추는 대신 그냥 쓰기를 거부해요. 이 스키마 드리프트를 막는 보호 장치예요.

새 컬럼이 늘어난 것처럼 **추가되는 변경**만 있다면 `mergeSchema` 옵션으로 허용할 수 있어요.

```python
df.write \
  .format("delta") \
  .option("mergeSchema", "true") \
  .mode("append") \
  .saveAsTable("sales")
```

`mergeSchema`는 소스에는 있지만 테이블에는 없는 컬럼을 추가해 줄 뿐이에요. 기존 컬럼을 지우거나 타입을 바꾸는 건 하지 않아요. 그래서 ETL 파이프라인에서 소스 스키마가 조금씩 늘어나는 상황에 가장 자주 쓰는 옵션이에요. 세션 전체에 자동 병합을 켜두고 싶다면 이렇게도 설정할 수 있어요.

```python
spark.conf.set("spark.databricks.delta.schema.autoMerge.enabled", True)
```

## 스키마를 통째로 바꿔야 할 때 — overwriteSchema

반대로 컬럼을 지우거나 타입을 바꾸는 등 스키마 자체를 완전히 새로 정의해야 할 때는 `overwriteSchema`를 써요.

```python
new_df.write \
  .format("delta") \
  .option("overwriteSchema", "true") \
  .mode("overwrite") \
  .saveAsTable("sales")
```

`overwriteSchema`는 테이블 정의 자체를 새 DataFrame의 스키마에 맞춰 다시 써요. `mergeSchema`보다 훨씬 파괴적인 옵션이에요. 이 테이블을 읽고 있던 SQL analytics endpoint, Power BI Direct Lake 모델, 다른 노트북이 옛 스키마를 기대하고 있었다면 그대로 깨질 수 있어요. 그래서 "제일 빠른 해결책"처럼 보여도, 운영 중인 테이블에는 신중하게 써야 하는 옵션이에요.

## 정리

`saveAsTable()`에서 `mode`는 기존 데이터를 지울지(overwrite) 쌓을지(append)를 정하는 스위치이고, `mergeSchema`·`overwriteSchema`는 스키마가 바뀌었을 때 그 변화를 얼마나 관대하게 받아들일지를 정하는 스위치예요. 컬럼이 늘어나는 정도라면 `mergeSchema`로 충분하고, 스키마를 아예 다시 정의해야 한다면 `overwriteSchema`를 쓰되 이 테이블을 읽는 다른 소비자들에게 미칠 영향을 먼저 점검하는 게 안전해요.