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.enabled
가true
인 경우
두 옵션이 모두 지정되면 DataFrameWriter
의 옵션이 우선 적용됩니다. 추가된 열은 해당 열이 있는 구조체의 끝에 추가됩니다. 대/소문자는 새 열을 추가할 때 유지됩니다.
참고 항목
mergeSchema
는INSERT INTO
또는.write.insertInto()
와 함께 사용할 수 없습니다.
Delta Lake 병합을 위한 자동 스키마 진화
스키마 진화를 통해 사용자는 병합에서 대상 테이블과 원본 테이블 간의 스키마 불일치를 해결할 수 있습니다. 다음 두 가지 경우를 처리합니다.
- 원본 테이블의 열이 대상 테이블에 없습니다. 새 열이 대상 스키마에 추가되고 해당 값은 원본 값을 사용하여 삽입되거나 업데이트됩니다.
- 대상 테이블의 열이 원본 테이블에 없습니다. 대상 스키마는 변경되지 않은 상태로 유지됩니다. 추가 대상 열의 값은 변경되지 않은 상태로 유지되거나(for
UPDATE
)로NULL
INSERT
설정됩니다.
Important
스키마 진화를 사용하려면 명령을 실행 merge
하기 전에 Spark 세션 구성 spark.databricks.delta.schema.autoMerge.enabled
을 true
설정해야 합니다.
참고 항목
- 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 * |
테이블 스키마가 변경되지 않은 상태로 유지되고, key 및 value 열만 업데이트/삽입됩니다. |
테이블 스키마가 (key, value, new_value) 로 변경됩니다. 일치 항목이 있는 기존 레코드는 원본에서 value new_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 가 원본에 없기 때문에 UPDATE 및 INSERT 동작이 오류를 throw합니다. |
테이블 스키마가 (key, old_value, new_value) 로 변경됩니다. 일치 항목이 있는 기존 레코드는 원본에서 new_value 변경되지 않은 상태로 업데이트 old_value 됩니다. 새 레코드는 지정된 레코드 및 에 대해 삽입됩니다 key NULL new_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) 로 변경됩니다. 새 레코드는 지정된 레코드 및 에 대해 삽입됩니다 key NULL new_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>> | 대상 테이블에 c 및 d 가 없기 때문에 update 및 insert 가 오류를 throw합니다. |
테이블 스키마가 array<struct<a: string, b: string, c: string, d: string>>으로 변경됩니다. 대상 테이블의 기존 항목에 대해 c 및 d 가 NULL 로 삽입됩니다. update 및 insert 가 원본 테이블에서 a 는 문자열로 캐스팅하고 b 는 NULL 로 캐스팅하여 항목을 채웁니다. |
array<struct<a: string, b: struct<c: string, d: string>>> | array<struct<a: string, b: struct<c: string>>> | 대상 테이블에 d 가 없기 때문에 update 및 insert 가 오류를 throw합니다. |
대상 테이블 스키마가 array<struct<a: string, b: struct<c: string, d: string>>>으로 변경됩니다. 대상 테이블의 기존 항목에 대해 d 가 NULL 로 삽입됩니다. |
스키마 업데이트에서 NullType
열 처리
Parquet는 NullType
을 지원하지 않으므로 델타 테이블에 쓸 때 NullType
열이 DataFrame에서 삭제되지만 스키마에는 계속 저장됩니다. 해당 열에 대해 다른 데이터 형식을 받으면 Delta Lake에서 스키마를 새 데이터 형식에 병합합니다. Delta Lake에서 기존 열에 대해 NullType
을 받으면 이전 스키마가 유지되고 쓰기 중에 새 열이 삭제됩니다.
스트리밍의 NullType
은 지원되지 않습니다. 스트리밍을 사용할 때 스키마를 설정해야 하므로 이는 매우 드문 경우입니다. NullType
은 ArrayType
및 MapType
과 같은 복합 형식에도 허용되지 않습니다.
테이블 스키마 바꾸기
기본적으로 테이블의 데이터를 덮어쓰더라도 스키마는 덮어쓰지 않습니다. replaceWhere
없이 mode("overwrite")
를 사용하여 테이블을 덮어쓰는 경우 여전히 쓰고 있는 데이터의 스키마를 덮어쓰려고 할 수 있습니다. overwriteSchema
옵션을 true
로 설정하여 테이블의 스키마 및 분할을 바꿉니다.
df.write.option("overwriteSchema", "true")
Important
동적 파티션 덮어쓰기를 사용할 때는 true
지정할 overwriteSchema
수 없습니다.