Delta Lake 테이블 스키마 업데이트

Delta Lake를 사용하면 테이블의 스키마를 업데이트할 수 있습니다. 지원되는 변경 유형은 다음과 같습니다.

  • 새 열 추가(임의의 위치에서)
  • 기존 열 순서 다시 지정
  • 기존 열 이름 바꾸기

이러한 변경은 DDL을 사용하여 명시적으로 수행하거나 DML을 사용하여 암시적으로 수행할 수 있습니다.

Important

델타 테이블 스키마에 대한 업데이트는 모든 동시 델타 쓰기 작업과 충돌하는 작업입니다.

델타 테이블 스키마를 업데이트하면 해당 테이블에서 읽는 스트림이 종료됩니다. 스트림을 계속하려면 다시 시작해야 합니다. 권장 방법은 구조적 스트리밍에 대한 프로덕션 고려 사항을 참조하세요.

스키마를 명시적으로 업데이트하여 열 추가

ALTER TABLE table_name ADD COLUMNS (col_name data_type [COMMENT col_comment] [FIRST|AFTER colA_name], ...)

기본적으로 null 허용 여부는 true입니다.

열을 중첩된 필드에 추가하려면 다음을 사용합니다.

ALTER TABLE table_name ADD COLUMNS (col_name.nested_col_name data_type [COMMENT col_comment] [FIRST|AFTER colA_name], ...)

예를 들어 ALTER TABLE boxes ADD COLUMNS (colB.nested STRING AFTER field1)를 실행하기 전의 스키마가 다음과 같은 경우가 있습니다.

- root
| - colA
| - colB
| +-field1
| +-field2

실행 이후 스키마는 다음과 같습니다.

- root
| - colA
| - colB
| +-field1
| +-nested
| +-field2

참고 항목

중첩 열 추가는 구조체에만 지원됩니다. 배열 및 맵은 지원되지 않습니다.

스키마를 명시적으로 업데이트하여 열 주석 또는 순서 변경

ALTER TABLE table_name ALTER [COLUMN] col_name (COMMENT col_comment | FIRST | AFTER colA_name)

중첩된 필드의 열을 변경하려면 다음을 사용합니다.

ALTER TABLE table_name ALTER [COLUMN] col_name.nested_col_name (COMMENT col_comment | FIRST | AFTER colA_name)

예를 들어 ALTER TABLE boxes ALTER COLUMN colB.field2 FIRST를 실행하기 전의 스키마가 다음과 같은 경우가 있습니다.

- root
| - colA
| - colB
| +-field1
| +-field2

실행 이후 스키마는 다음과 같습니다.

- root
| - colA
| - colB
| +-field2
| +-field1

스키마를 명시적으로 업데이트하여 열 바꾸기

ALTER TABLE table_name REPLACE COLUMNS (col_name1 col_type1 [COMMENT col_comment1], ...)

예를 들어 다음 DDL을 실행하는 경우:

ALTER TABLE boxes REPLACE COLUMNS (colC STRING, colB STRUCT<field2:STRING, nested:STRING, field1:STRING>, colA STRING)

실행 이전 스키마는 다음과 같습니다.

- root
| - colA
| - colB
| +-field1
| +-field2

실행 이후 스키마는 다음과 같습니다.

- root
| - colC
| - colB
| +-field2
| +-nested
| +-field1
| - colA

스키마를 명시적으로 업데이트하여 열 이름 변경

Important

이 기능은 공개 미리 보기 상태입니다.

참고 항목

이 기능은 Databricks Runtime 10.4 LTS 이상에서 사용할 수 있습니다.

열의 기존 데이터를 다시 쓰지 않고 열 이름을 바꾸려면 열 매핑을 테이블에 사용하도록 설정해야 합니다. Delta Lake 열 매핑을 사용하여 열 이름 바꾸기 및 삭제를 참조 하세요.

열 이름을 바꾸려면 다음을 수행합니다.

ALTER TABLE table_name RENAME COLUMN old_col_name TO new_col_name

중첩된 필드의 이름을 바꾸려면 다음을 수행합니다.

ALTER TABLE table_name RENAME COLUMN col_name.old_nested_field TO new_nested_field

예를 들어 다음 명령을 실행하는 경우:

ALTER TABLE boxes RENAME COLUMN colB.field1 TO field001

실행 이전 스키마는 다음과 같습니다.

- root
| - colA
| - colB
| +-field1
| +-field2

실행 이후 스키마는 다음과 같습니다.

- root
| - colA
| - colB
| +-field001
| +-field2

Delta Lake 열 매핑을 사용하여 열 이름 바꾸기 및 삭제를 참조 하세요.

스키마를 명시적으로 업데이트하여 열 삭제

Important

이 기능은 공개 미리 보기 상태입니다.

참고 항목

이 기능은 Databricks Runtime 11.3 LTS 이상에서 사용할 수 있습니다.

데이터 파일을 다시 작성하지 않고 메타데이터 전용 작업으로 열을 삭제하려면 테이블에 대한 열 매핑을 사용하도록 설정해야 합니다. Delta Lake 열 매핑을 사용하여 열 이름 바꾸기 및 삭제를 참조 하세요.

Important

메타데이터에서 열을 삭제해도 파일의 열에 대한 기본 데이터는 삭제되지 않습니다. 삭제된 열 데이터를 제거하려면 REORG TABLE을 사용하여 파일을 다시 작성하면 됩니다. 그런 다음, VACUUM을 사용하여 삭제된 열 데이터가 포함된 파일을 물리적으로 삭제할 수 있습니다.

열을 삭제하려면 다음을 수행합니다.

ALTER TABLE table_name DROP COLUMN col_name

여러 열을 삭제하려면 다음을 수행합니다.

ALTER TABLE table_name DROP COLUMNS (col_name_1, col_name_2)

스키마를 명시적으로 업데이트하여 열 형식 또는 이름 변경

테이블을 다시 작성하여 열의 형식 또는 이름을 변경하거나 열을 삭제할 수 있습니다. 이렇게 하려면 overwriteSchema 옵션을 사용합니다.

다음 예제에서는 열 형식을 변경하는 방법을 보여줍니다.

(spark.read.table(...)
  .withColumn("birthDate", col("birthDate").cast("date"))
  .write
  .mode("overwrite")
  .option("overwriteSchema", "true")
  .saveAsTable(...)
)

다음 예제에서는 열 이름을 변경하는 방법을 보여줍니다.

(spark.read.table(...)
  .withColumnRenamed("dateOfBirth", "birthDate")
  .write
  .mode("overwrite")
  .option("overwriteSchema", "true")
  .saveAsTable(...)
)

자동 스키마 업데이트로 열 추가

DataFrame에 있지만 테이블에서 누락된 열은 다음과 같은 경우 쓰기 트랜잭션의 일부로 자동으로 추가됩니다.

  • write 또는 writeStream.option("mergeSchema", "true")가 있습니다.
  • spark.databricks.delta.schema.autoMerge.enabledtrue인 경우

두 옵션이 모두 지정되면 DataFrameWriter의 옵션이 우선 적용됩니다. 추가된 열은 해당 열이 있는 구조체의 끝에 추가됩니다. 대/소문자는 새 열을 추가할 때 유지됩니다.

참고 항목

  • mergeSchemaINSERT INTO 또는 .write.insertInto()와 함께 사용할 수 없습니다.

Delta Lake 병합을 위한 자동 스키마 진화

스키마 진화를 통해 사용자는 병합에서 대상 테이블과 원본 테이블 간의 스키마 불일치를 해결할 수 있습니다. 다음 두 가지 경우를 처리합니다.

  1. 원본 테이블의 열이 대상 테이블에 없습니다. 새 열이 대상 스키마에 추가되고 해당 값은 원본 값을 사용하여 삽입되거나 업데이트됩니다.
  2. 대상 테이블의 열이 원본 테이블에 없습니다. 대상 스키마는 변경되지 않은 상태로 유지됩니다. 추가 대상 열의 값은 변경되지 않은 상태로 유지되거나(for UPDATE)로 NULLINSERT설정됩니다.

Important

스키마 진화를 사용하려면 명령을 실행 merge 하기 전에 Spark 세션 구성 spark.databricks.delta.schema.autoMerge.enabledtrue 설정해야 합니다.

참고 항목

  • Databricks Runtime 12.2 LTS 이상에서는 원본 테이블에 있는 열을 삽입 또는 업데이트 작업의 이름으로 지정할 수 있습니다. Databricks Runtime 11.3 LTS 이하에서는 병합을 사용하여 스키마 진화에만 INSERT * 또는 UPDATE SET * 작업을 사용할 수 있습니다.

다음은 스키마 개선이 사용된 경우와 사용되지 않은 경우에 merge 작업의 효과를 보여 주는 몇 가지 예제입니다.

쿼리(SQL) 스키마 개선이 사용되지 않은 동작(기본값) 스키마가 개선이 사용된 동작
대상 열: key, value

원본 열: key, value, new_value
MERGE INTO target_table t
USING source_table s
ON t.key = s.key
WHEN MATCHED
THEN UPDATE SET *
WHEN NOT MATCHED
THEN INSERT *
테이블 스키마가 변경되지 않은 상태로 유지되고, keyvalue 열만 업데이트/삽입됩니다. 테이블 스키마가 (key, value, new_value)로 변경됩니다. 일치 항목이 있는 기존 레코드는 원본에서 valuenew_value 업데이트됩니다. 스키마 (key, value, new_value)와 함께 새 행이 삽입됩니다.
대상 열: key, old_value

원본 열: key, new_value
MERGE INTO target_table t
USING source_table s
ON t.key = s.key
WHEN MATCHED
THEN UPDATE SET *
WHEN NOT MATCHED
THEN INSERT *
대상 열 old_value가 원본에 없기 때문에 UPDATEINSERT 동작이 오류를 throw합니다. 테이블 스키마가 (key, old_value, new_value)로 변경됩니다. 일치 항목이 있는 기존 레코드는 원본에서 new_value 변경되지 않은 상태로 업데이트 old_value 됩니다. 새 레코드는 지정된 레코드 및 에 대해 삽입됩니다 keyNULLnew_value.old_value
대상 열: key, old_value

원본 열: key, new_value
MERGE INTO target_table t
USING source_table s
ON t.key = s.key
WHEN MATCHED
THEN UPDATE SET new_value = s.new_value
new_value 열이 대상 테이블에 없기 때문에 UPDATE가 오류를 throw합니다. 테이블 스키마가 (key, old_value, new_value)로 변경됩니다. 일치 항목이 있는 기존 레코드는 원본에서 new_value 변경되지 않은 상태로 old_value 업데이트되고 일치하지 않는 레코드가 NULL 입력되었습니다 new_value. 참고 (1)를 참조하세요.
대상 열: key, old_value

원본 열: key, new_value
MERGE INTO target_table t
USING source_table s
ON t.key = s.key
WHEN NOT MATCHED
THEN INSERT (key, new_value) VALUES (s.key, s.new_value)
new_value 열이 대상 테이블에 없기 때문에 INSERT가 오류를 throw합니다. 테이블 스키마가 (key, old_value, new_value)로 변경됩니다. 새 레코드는 지정된 레코드 및 에 대해 삽입됩니다 keyNULLnew_value.old_value 기존 레코드는 NULL 변경되지 않은 상태로 두 old_value 기 위해 new_value 입력되었습니다. 참고 (1)를 참조하세요.

(1) 이 동작은 Databricks Runtime 12.2 LTS 이상에서 사용할 수 있습니다. 이 조건의 Databricks Runtime 11.3 LTS 이하 오류입니다.

Delta Lake 병합을 사용하여 열 제외

Databricks Runtime 12.2 LTS 이상에서는 병합 조건에서 절을 사용하여 EXCEPT 열을 명시적으로 제외할 수 있습니다. 키워드(keyword) 동작 EXCEPT 은 스키마 진화를 사용하는지 여부에 따라 달라집니다.

스키마 진화를 EXCEPT 사용하지 않도록 설정하면 키워드(keyword) 대상 테이블의 열 목록에 적용되며 열 또는 INSERT 작업에서 UPDATE 열을 제외할 수 있습니다. 제외된 열은 .로 null설정됩니다.

스키마 진화를 EXCEPT 사용하도록 설정하면 키워드(keyword) 원본 테이블의 열 목록에 적용되며 스키마 진화에서 열을 제외할 수 있습니다. 대상에 없는 원본의 새 열은 절에 나열된 경우 대상 스키마에 EXCEPT 추가되지 않습니다. 대상에 이미 있는 제외된 열은 .로 null설정됩니다.

다음 예제에서는 이 구문을 보여 줍니다.

쿼리(SQL) 스키마 개선이 사용되지 않은 동작(기본값) 스키마가 개선이 사용된 동작
대상 열: id, title, last_updated

원본 열: id, title, review, last_updated
MERGE INTO target t
USING source s
ON t.id = s.id
WHEN MATCHED
THEN UPDATE SET last_updated = current_date()
WHEN NOT MATCHED
THEN INSERT * EXCEPT (last_updated)
일치하는 행은 필드를 현재 날짜로 설정 last_updated 하여 업데이트됩니다. 새 행은 에 대한 id 값을 사용하여 삽입됩니다 title. 제외된 필드는 last_updated .로 설정됩니다 null. review 필드가 대상에 없으므로 무시됩니다. 일치하는 행은 필드를 현재 날짜로 설정 last_updated 하여 업데이트됩니다. 스키마가 진화하여 필드를 review추가합니다. 로 설정된 null행을 제외한 last_updated 모든 원본 필드를 사용하여 새 행이 삽입됩니다.
대상 열: id, title, last_updated

원본 열: id, title, review, internal_count
MERGE INTO target t
USING source s
ON t.id = s.id
WHEN MATCHED
THEN UPDATE SET last_updated = current_date()
WHEN NOT MATCHED
THEN INSERT * EXCEPT (last_updated, internal_count)
internal_count 열이 대상 테이블에 없기 때문에 INSERT가 오류를 throw합니다. 일치하는 행은 필드를 현재 날짜로 설정 last_updated 하여 업데이트됩니다. 필드 review 가 대상 테이블에 추가되지만 internal_count 필드는 무시됩니다. 삽입된 새 행이 .로 null설정되었습니다last_updated.

구조체 배열을 위한 자동 스키마 진화

델타 MERGE INTO는 구조체 필드를 이름으로 확인하고 구조체로 구성된 배열의 스키마를 개선합니다. 스키마 개선이 사용하도록 설정된 경우, 구조체로 구성된 배열의 대상 테이블 스키마가 개선되며, 여기에는 배열 내에 있는 중첩된 구조체도 포함됩니다.

참고 항목

Databricks Runtime 12.2 LTS 이상에서는 원본 테이블에 있는 구조체 필드를 삽입 또는 업데이트 명령의 이름으로 지정할 수 있습니다. Databricks Runtime 11.3 LTS 이하에서는 병합을 사용하여 스키마 진화에만 INSERT * 또는 UPDATE SET * 명령을 사용할 수 있습니다.

다음은 구조체로 구성된 배열에 대한 스키마 개선이 사용된 경우와 사용되지 않은 경우의 병합 작업의 효과를 보여 주는 몇 가지 예입니다.

원본 스키마 대상 스키마 스키마 개선이 사용되지 않은 동작(기본값) 스키마가 개선이 사용된 동작
array<struct<b: string, a: string>> array<struct<a: int, b: int>> 테이블 스키마가 변경되지 않은 상태로 유지됩니다. 열이 이름으로 확인되고 업데이트 또는 삽입됩니다. 테이블 스키마가 변경되지 않은 상태로 유지됩니다. 열이 이름으로 확인되고 업데이트 또는 삽입됩니다.
array<struct<a: int, c: string, d: string>> array<struct<a: string, b: string>> 대상 테이블에 cd가 없기 때문에 updateinsert가 오류를 throw합니다. 테이블 스키마가 array<struct<a: string, b: string, c: string, d: string>>으로 변경됩니다. 대상 테이블의 기존 항목에 대해 cdNULL로 삽입됩니다. updateinsert가 원본 테이블에서 a는 문자열로 캐스팅하고 bNULL로 캐스팅하여 항목을 채웁니다.
array<struct<a: string, b: struct<c: string, d: string>>> array<struct<a: string, b: struct<c: string>>> 대상 테이블에 d가 없기 때문에 updateinsert가 오류를 throw합니다. 대상 테이블 스키마가 array<struct<a: string, b: struct<c: string, d: string>>>으로 변경됩니다. 대상 테이블의 기존 항목에 대해 dNULL로 삽입됩니다.

스키마 업데이트에서 NullType 열 처리

Parquet는 NullType을 지원하지 않으므로 델타 테이블에 쓸 때 NullType 열이 DataFrame에서 삭제되지만 스키마에는 계속 저장됩니다. 해당 열에 대해 다른 데이터 형식을 받으면 Delta Lake에서 스키마를 새 데이터 형식에 병합합니다. Delta Lake에서 기존 열에 대해 NullType을 받으면 이전 스키마가 유지되고 쓰기 중에 새 열이 삭제됩니다.

스트리밍의 NullType은 지원되지 않습니다. 스트리밍을 사용할 때 스키마를 설정해야 하므로 이는 매우 드문 경우입니다. NullTypeArrayTypeMapType과 같은 복합 형식에도 허용되지 않습니다.

테이블 스키마 바꾸기

기본적으로 테이블의 데이터를 덮어쓰더라도 스키마는 덮어쓰지 않습니다. replaceWhere 없이 mode("overwrite")를 사용하여 테이블을 덮어쓰는 경우 여전히 쓰고 있는 데이터의 스키마를 덮어쓰려고 할 수 있습니다. overwriteSchema 옵션을 true로 설정하여 테이블의 스키마 및 분할을 바꿉니다.

df.write.option("overwriteSchema", "true")

Important

동적 파티션 덮어쓰기를 사용할 때는 true 지정할 overwriteSchema 수 없습니다.