Mettre à jour les schémas de table avec l'évolution des schémas
Les tables prennent en charge l'évolution des schémas, permettant des modifications de la structure des tables à mesure que les exigences en matière de données évoluent. Les types de modifications suivants sont pris en charge :
- Ajout de nouvelles colonnes à des positions arbitraires
- Réorganisation des colonnes existantes
- Renommage des colonnes existantes
- Élargissement des types des colonnes existantes, voir Élargir les types avec l'évolution automatique des schémas
Apportez ces modifications explicitement en utilisant DDL ou implicitement en utilisant DML.
Les mises à jour de schéma entrent en conflit avec toutes les opérations d'écriture concurrentes. Databricks recommande de coordonner les modifications de schéma afin d’éviter les conflits d’écriture.
La mise à jour d'un schéma de table met fin à tous les Streams qui lisent cette table. Pour continuer le traitement, redémarrez le stream en utilisant les méthodes décrites dans Considérations de production pour le Structured Streaming.
Modifications manuelles du schéma
Utilisez des instructions ALTER TABLE pour modifier explicitement le schéma d'une table sans écrire de nouvelles données.
Ajouter des colonnes
Utilisez ALTER TABLE ... ADD COLUMNS pour ajouter une ou plusieurs colonnes à une table existante, en spécifiant éventuellement la position et un commentaire :
ALTER TABLE table_name ADD COLUMNS (col_name data_type [COMMENT col_comment] [FIRST|AFTER colA_name], ...)
Par défaut, la nullabilité est true.
Exemple : Ajouter des champs imbriqués
L'ajout de colonnes imbriquées est pris en charge uniquement pour les structs. Les tableaux et les cartes ne sont pas pris en charge.
Pour ajouter une colonne à un champ imbriqué, utilisez :
ALTER TABLE table_name ADD COLUMNS (col_name.nested_col_name data_type [COMMENT col_comment] [FIRST|AFTER colA_name], ...)
Par exemple, si le schéma avant d'exécuter ALTER TABLE boxes ADD COLUMNS (colB.nested STRING AFTER field1) est :
- root
| - colA
| - colB
| +-field1
| +-field2
le schéma est le suivant :
- root
| - colA
| - colB
| +-field1
| +-nested
| +-field2
Modifier les commentaires et l'ordre des colonnes
Utilisez ALTER TABLE ... ALTER COLUMN pour mettre à jour le commentaire d'une colonne ou pour la réorganiser par rapport aux autres colonnes :
ALTER TABLE table_name ALTER [COLUMN] col_name (COMMENT col_comment | FIRST | AFTER colA_name)
Exemple : modifier les champs imbriqués
Pour modifier une colonne dans un champ imbriqué, utilisez :
ALTER TABLE table_name ALTER [COLUMN] col_name.nested_col_name (COMMENT col_comment | FIRST | AFTER colA_name)
Par exemple, si le schéma avant d'exécuter ALTER TABLE boxes ALTER COLUMN colB.field2 FIRST est :
- root
| - colA
| - colB
| +-field1
| +-field2
le schéma est le suivant :
- root
| - colA
| - colB
| +-field2
| +-field1
Remplacer les colonnes
Utilisez ALTER TABLE ... REPLACE COLUMNS pour redéfinir la liste complète des colonnes d'une table, y compris l'ajout, la suppression, le réordonnancement ou le renommage de colonnes en une seule opération :
ALTER TABLE table_name REPLACE COLUMNS (col_name1 col_type1 [COMMENT col_comment1], ...)
Exemple : remplacer les champs imbriqués
Par exemple, lors de l'exécution du DDL suivant :
ALTER TABLE boxes REPLACE COLUMNS (colC STRING, colB STRUCT<field2:STRING, nested:STRING, field1:STRING>, colA STRING)
si le schéma précédent est :
- root
| - colA
| - colB
| +-field1
| +-field2
le schéma est le suivant :
- root
| - colC
| - colB
| +-field2
| +-nested
| +-field1
| - colA
Renommer les colonnes
Pour renommer des colonnes sans réécrire les données existantes des colonnes, vous devez activer le mappage des colonnes pour la table. Consultez Renommer et supprimer des colonnes avec le mappage de colonnes Delta Lake.
Pour renommer une colonne :
ALTER TABLE table_name RENAME COLUMN old_col_name TO new_col_name
Exemple : Renommer les champs imbriqués
Renommer un champ imbriqué :
ALTER TABLE table_name RENAME COLUMN col_name.old_nested_field TO new_nested_field
Par exemple, lorsque vous exécutez la commande suivante :
ALTER TABLE boxes RENAME COLUMN colB.field1 TO field001
Si le schéma précédent est :
- root
| - colA
| - colB
| +-field1
| +-field2
Ensuite le schéma après est :
- root
| - colA
| - colB
| +-field001
| +-field2
Voir Renommer et supprimer des colonnes avec le mappage de colonnes Delta Lake.
Supprimer des colonnes
Pour supprimer des colonnes en tant qu'opération de métadonnées uniquement sans réécrire les fichiers de données, vous devez activer le mappage des colonnes pour la table. Consultez Renommer et supprimer des colonnes avec le mappage de colonnes Delta Lake.
La suppression d'une colonne des métadonnées ne supprime pas les données sous-jacentes de la colonne dans les fichiers. Pour purger les données de colonne supprimées :
- Utilisez REORG TABLE pour réécrire les fichiers.
- Utilisez ensuite VACUUM pour supprimer physiquement les fichiers qui contiennent les données des colonnes supprimées.
Pour supprimer une colonne :
ALTER TABLE table_name DROP COLUMN col_name
Pour supprimer plusieurs colonnes :
ALTER TABLE table_name DROP COLUMNS (col_name_1, col_name_2)
Modifier le type ou le nom de la colonne
Vous pouvez modifier le type ou le nom d'une colonne ou supprimer une colonne en réécrivant la table. Pour ce faire, utilisez l'option overwriteSchema.
L'exemple suivant montre le changement d'un type de colonne :
(spark.read.table(...)
.withColumn("birthDate", col("birthDate").cast("date"))
.write
.mode("overwrite")
.option("overwriteSchema", "true")
.saveAsTable(...)
)
L'exemple suivant présente la modification d'un nom de colonne :
(spark.read.table(...)
.withColumnRenamed("dateOfBirth", "birthDate")
.write
.mode("overwrite")
.option("overwriteSchema", "true")
.saveAsTable(...)
)
Activer l'évolution des schémas
Utilisez WITH SCHEMA EVOLUTION ou définissez mergeSchema sur true pour apporter des modifications de schéma en fonction du schéma des données que vous souhaitez INSERT ou MERGE dans une table existante.
Activer l'évolution des schémas en utilisant l'une des méthodes suivantes :
- Utiliser la syntaxe
INSERT WITH SCHEMA EVOLUTIONpour les instructionsINSERT. - Utilisez la syntaxe
MERGE WITH SCHEMA EVOLUTIONpour les instructions avecMERGE. Utilisez soitWITH SCHEMA EVOLUTIONdans la syntaxe SQL, soit.withSchemaEvolution()dans l'API Databricks. - Définissez l'option
mergeSchemapour les écritures batch ou streaming. Définissez.option("mergeSchema", "true")sur les opérations d'écriture individuelles. - Définir la configuration Spark (héritée) : Définit
spark.databricks.delta.schema.autoMerge.enabledsurtruepour l'ensemble de la SparkSession.
Databricks recommande d'activer l'évolution des schémas pour chaque opération d'écriture en utilisant la syntaxe WITH SCHEMA EVOLUTION ou l'option mergeSchema plutôt que de définir une configuration Spark.
Lorsque vous utilisez des options ou une syntaxe pour activer l'évolution des schémas dans une opération d'écriture, cela prévaut sur la configuration Spark.
Activez l'évolution des schémas pour les écritures afin d'ajouter de nouvelles colonnes
Lorsque l'évolution des schémas est activée, les colonnes présentes dans la query source mais absentes de la table cible sont automatiquement ajoutées dans le cadre d'une transaction d'écriture. Consultez Activer l'évolution des schémas.
Considérons les éléments suivants :
- La casse est conservée lors de l'ajout d'une nouvelle colonne.
- Les nouvelles colonnes sont ajoutées à la fin du schéma de la table.
- Si les colonnes supplémentaires se trouvent dans une structure, elles sont ajoutées à la fin de la structure dans la table cible.
INSERT avec évolution des schémas à l'aide de SQL
Utilisez la clause WITH SCHEMA EVOLUTION dans les instructions INSERT pour activer l'évolution des schémas :
INSERT WITH SCHEMA EVOLUTION INTO target_table
SELECT * FROM source_table
Si la query sur source_table renvoie des colonnes qui n'existent pas dans la table cible, ces colonnes sont automatiquement ajoutées au schéma target_table. Les lignes existantes reçoivent NULL valeurs pour les nouvelles colonnes.
INSERT avec évolution des schémas à l'aide de l'API DataFrame
L'exemple suivant illustre l'utilisation de l'option mergeSchema avec une opération d'écriture par batch :
- Python
- Scala
(spark.read
.table("source_table")
.write
.option("mergeSchema", "true")
.mode("append")
.saveAsTable("target_table")
)
spark.read
.table("source_table")
.write
.option("mergeSchema", "true")
.mode("append")
.saveAsTable("target_table")
INSERT avec évolution des schémas avec Structured Streaming
L’exemple suivant montre comment utiliser l’option mergeSchema avec Auto Loader pour Structured Streaming. Consultez Qu’est-ce qu’Auto Loader ?.
(spark.readStream
.format("cloudFiles")
.option("cloudFiles.format", "json")
.option("cloudFiles.schemaLocation", "<path-to-schema-location>")
.load("<path-to-source-data>")
.writeStream
.option("mergeSchema", "true")
.option("checkpointLocation", "<path-to-checkpoint>")
.trigger(availableNow=True)
.toTable("table_name")
)
Évolution automatique des schémas pour le merge
Pour MERGE, l’évolution des schémas vous permet de résoudre les non-concordances de schémas entre la table cible et la table source. Il gère les deux cas suivants :
-
Une colonne existe dans la table source mais pas dans la table cible, et est spécifiée par son nom dans une affectation d'actions d'insertion ou de mise à jour. Alternativement, une action
UPDATE SET *ouINSERT *est présente.Cette colonne sera ajoutée au schéma cible, et ses valeurs seront renseignées à partir de la colonne correspondante dans la source.
-
Ceci ne s'applique que lorsque le nom de la colonne et la structure dans la source de Merge correspondent exactement à l'affectation cible.
-
La nouvelle colonne doit être présente dans le schéma source. L'affectation de la nouvelle colonne dans la clause d'action ne définit pas cette colonne.
Ces exemples permettent l'évolution des schémas :
SQL-- The column newcol is present in the source but not in the target. It will be added to the target.
UPDATE SET target.newcol = source.newcol
-- The field newfield doesn't exist in struct column somestruct of the target. It will be added to that struct column.
UPDATE SET target.somestruct.newfield = source.somestruct.newfield
-- The column newcol is present in the source but not in the target.
-- It will be added to the target.
UPDATE SET target.newcol = source.newcol + 1
-- Any columns and nested fields in the source that don't exist in target will be added to the target.
UPDATE SET *
INSERT *Ces exemples ne trigger pas l'évolution des schémas si la colonne
newcoln'est pas présente dans le schémasource:SQLUPDATE SET target.newcol = source.someothercol
UPDATE SET target.newcol = source.x + source.y
UPDATE SET target.newcol = source.output.newcol -
-
Une colonne existe dans la table cible mais pas dans la table source.
Le schéma cible n'est pas modifié. Ces colonnes :
-
Sont laissés inchangés pour
UPDATE SET *. -
Sont définis sur
NULLpourINSERT *. -
Pourrait toujours être explicitement modifié s’il est attribué dans la clause d’action.
Par exemple :
SQLUPDATE SET * -- The target columns that are not in the source are left unchanged.
INSERT * -- The target columns that are not in the source are set to NULL.
UPDATE SET target.onlyintarget = 5 -- The target column is explicitly updated.
UPDATE SET target.onlyintarget = source.someothercol -- The target column is explicitly updated from some other source column. -
Vous devez activer manuellement l'évolution automatique des schémas. Consultez Activer l'évolution des schémas.
Dans Databricks Runtime 11.3 LTS et versions antérieures, seules les actions INSERT * ou UPDATE SET * peuvent être utilisées pour l'évolution des schémas avec Merge.
Dans Databricks Runtime 12.2 LTS et versions ultérieures, les colonnes et les champs struct présents dans la table source peuvent être spécifiés par leur nom dans les actions d'insertion ou de mise à jour.
Dans Databricks Runtime 13.3 LTS et versions ultérieures, vous pouvez utiliser l'évolution des schémas avec des structs imbriquées dans des maps, telles que map<int, struct<a: int, b: int>>.
MERGE avec évolution des schémas utilisant SQL, Python et Scala
Dans Databricks Runtime 15.4 LTS et versions ultérieures, vous pouvez spécifier l'évolution des schémas dans une instruction de Merge en utilisant SQL ou les APIs de table :
- SQL
- Python
- Scala
MERGE WITH SCHEMA EVOLUTION INTO target
USING source
ON source.key = target.key
WHEN MATCHED THEN
UPDATE SET *
WHEN NOT MATCHED THEN
INSERT *
WHEN NOT MATCHED BY SOURCE THEN
DELETE
from delta.tables import *
(targetTable
.merge(sourceDF, "source.key = target.key")
.withSchemaEvolution()
.whenMatchedUpdateAll()
.whenNotMatchedInsertAll()
.whenNotMatchedBySourceDelete()
.execute()
)
import io.delta.tables._
targetTable
.merge(sourceDF, "source.key = target.key")
.withSchemaEvolution()
.whenMatched()
.updateAll()
.whenNotMatched()
.insertAll()
.whenNotMatchedBySource()
.delete()
.execute()
Exemple d'opérations de MERGE avec évolution des schémas
Voici quelques exemples des effets de l'opération MERGE avec et sans évolution des schémas.
Colonnes | query (en SQL) | Comportement sans évolution des schémas (default) | Comportement avec l'évolution des schémas |
|---|---|---|---|
Colonnes cibles : Colonnes source: | SQL | Le schéma de la table reste inchangé ; seules les colonnes | Le schéma de la table est modifié en |
Colonnes cibles : Colonnes source: | SQL |
| Le schéma de la table est modifié en |
Colonnes cibles : Colonnes source: | SQL |
| Le schéma de la table est modifié en |
Colonnes cibles : Colonnes source: | SQL |
| Le schéma de la table est modifié en |
(1) Ce comportement est disponible dans Databricks Runtime 12.2 LTS et versions ultérieures ; Databricks Runtime 11.3 LTS et versions antérieures génèrent une erreur dans cette condition.
Exclure des colonnes avec Merge
Dans Databricks Runtime 12.2 LTS et versions ultérieures, vous pouvez utiliser les clauses EXCEPT dans les conditions Merge pour exclure explicitement des colonnes. Le comportement du mot-clé EXCEPT varie selon que l'évolution des schémas est activée ou non.
Lorsque l'évolution des schémas est désactivée, le mot-clé EXCEPT s'applique à la liste des colonnes de la table cible et permet d'exclure des colonnes des actions UPDATE ou INSERT. Les colonnes exclues sont définies sur null.
Avec l’évolution des schémas activée, le mot-clé EXCEPT s’applique à la liste des colonnes dans la table source et permet d’exclure des colonnes de l’évolution des schémas. Une nouvelle colonne dans la source, non présente dans la table cible, n'est pas ajoutée au schéma cible si elle est listée dans la clause EXCEPT. Les colonnes exclues qui sont déjà présentes dans la cible sont définies sur null.
Exemples de EXCLUDE avec MERGE
Les exemples suivants illustrent cette syntaxe :
Colonnes | query (en SQL) | Comportement sans évolution des schémas (default) | Comportement avec l'évolution des schémas |
|---|---|---|---|
Colonnes cibles : Colonnes source: | SQL | Les lignes correspondantes sont mises à jour en définissant le champ | Les lignes correspondantes sont mises à jour en définissant le champ |
Colonnes cibles : Colonnes source: | SQL |
| Les lignes correspondantes sont mises à jour en définissant le champ |
Activer l'évolution des schémas avec la configuration Spark (hérité)
Vous pouvez définir la configuration Spark spark.databricks.delta.schema.autoMerge.enabled sur true pour activer l'évolution des schémas pour toutes les opérations d'écriture dans la SparkSession actuelle :
- Python
- Scala
- SQL
spark.conf.set("spark.databricks.delta.schema.autoMerge.enabled", True)
spark.conf.set("spark.databricks.delta.schema.autoMerge.enabled", true)
SET spark.databricks.delta.schema.autoMerge.enabled=true
Databricks ne recommande pas cette approche pour la production. La définition d'une configuration à l'échelle de la session pourrait entraîner des modifications de schéma involontaires à travers de multiples opérations et rend plus difficile de déterminer quelles opérations font évoluer le schéma.
Au lieu de cela, activez l'évolution des schémas pour chaque opération d'écriture :
- Pour
INSERTet les écritures batch/streaming, utilisez.option("mergeSchema", "true")ouINSERT WITH SCHEMA EVOLUTION"> - Pour
MERGEinstructions, utilisezMERGE WITH SCHEMA EVOLUTION
Lorsque vous utilisez des options ou une syntaxe pour activer l'évolution des schémas dans une opération d'écriture, cela prévaut sur la configuration Spark.
Remplacer le schéma de table
By default, l'écrasement des données d'une table n'écrase pas le schéma. Lorsque vous remplacez une table en utilisant mode("overwrite") sans replaceWhere, vous pourriez toujours vouloir remplacer le schéma des données en cours d'écriture.
Pour remplacer le schéma et le partitionnement de la table, définissez l'option overwriteSchema sur true:
df.write.option("overwriteSchema", "true")
Vous ne pouvez pas spécifier overwriteSchema comme true lorsque vous utilisez l'écrasement dynamique de partition. Consultez écrasements dynamiques de partition avec partitionOverwriteMode (hérité).