Dans le monde du big data, une gestion efficace des données est cruciale. Grâce à ses propriétés ACID et à ses optimisations de performance, Delta Lake constitue une base robuste. Une de ses fonctionnalités clés pour maintenir des performances optimales est la data compaction, aussi appelée opération OPTIMIZE
. Cet article explore en profondeur la data compaction dans les Delta Tables, et fournit un guide complet pour les data engineers et les architectes.
Qu’est-ce que la Data Compaction et pourquoi est-ce important ?
La data compaction consiste à fusionner les petits fichiers d’une Delta Table en fichiers plus volumineux. Au fil du temps, en raison des insertions, mises à jour ou suppressions, une table peut accumuler un grand nombre de petits fichiers, ce qui entraîne :
- Dégradation des performances des requêtes : lire de nombreux petits fichiers génère une surcharge importante (I/O, métadonnées, scheduling), ce qui ralentit l’exécution des requêtes.
- Augmentation des coûts de stockage : les systèmes de fichiers ont souvent une taille minimale allouée par fichier, entraînant du gaspillage lorsque de nombreux petits fichiers sont présents. Les métadonnées prennent aussi de la place.
- Gestion inefficace des données : trop de fichiers compliquent les sauvegardes, la restauration et la gestion du cycle de vie des données.
La data compaction résout ces problèmes en consolidant les fichiers, ce qui permet :
- Amélioration des performances : moins de fichiers = moins de surcharge I/O = exécutions plus rapides.
- Réduction des coûts de stockage : consolidation = espace optimisé.
- Gestion simplifiée : moins de fichiers = gestion plus facile.
Comment fonctionne la Data Compaction dans Delta Lake
La data compaction repose sur plusieurs mécanismes internes :
Fusion et réécriture de fichiers
Quand vous exécutez OPTIMIZE
, Delta Lake identifie les petits fichiers (en fonction d’un seuil configuré) et les fusionne. Le processus comprend :
- Identification des petits fichiers
- Lecture des données
- Fusion et réécriture en fichiers Parquet plus gros
- Enregistrement dans le transaction log comme une transaction atomique
- Mise à jour des métadonnées : les nouveaux fichiers remplacent les anciens
Stratégies et options de compaction
Delta Lake permet de configurer la compaction :
- Taille cible des fichiers : souvent 1 Go, mais à ajuster selon le workload
- Partitionnement : possibilité de compacter uniquement certaines partitions
- Z-Ordering : clusterisation spatiale des données basée sur des colonnes spécifiques pour améliorer les performances de filtrage/join
spark.databricks.delta.optimize.maxFileSize
: taille cible pourOPTIMIZE
(au niveau cluster)spark.databricks.delta.optimize.minPartitions
: nombre minimal de partitions pour parallélisme
Intégration avec le Transaction Log
Chaque OPTIMIZE
est enregistré comme une transaction Delta :
- Atomicité : l’opération est “tout ou rien”
- Cohérence : la table reste lisible et valide à tout moment
- Durabilité : les changements sont persistés même en cas de crash
Cela permet aussi le time travel vers l’état avant ou après la compaction.
Compaction en pratique : Exemples de code
PySpark
from pyspark.sql import SparkSession
from delta.tables import DeltaTable
spark = SparkSession.builder.appName("DeltaCompaction").getOrCreate()
table_path = "/path/to/my_delta_table"
# OPTIMIZE de base
spark.sql(f"OPTIMIZE delta.`{table_path}`")
# OPTIMIZE avec filtre de date
spark.sql(f"OPTIMIZE delta.`{table_path}` WHERE date >= '2023-01-01' AND date < '2023-02-01'")
# OPTIMIZE avec Z-Ordering
spark.sql(f"OPTIMIZE delta.`{table_path}` ZORDER BY (id)")
# API DeltaTable
deltaTable = DeltaTable.forPath(spark, table_path)
deltaTable.optimize().executeCompaction()
deltaTable.optimize().where("date >= '2023-01-01' AND date < '2023-02-01'").executeCompaction()
deltaTable.optimize().zOrderBy("id").executeCompaction()
spark.stop()
Scala
import org.apache.spark.sql.SparkSession
import io.delta.tables._
object DeltaCompaction {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder().appName("DeltaCompaction").getOrCreate()
val tablePath = "/path/to/my_delta_table"
spark.sql(s"OPTIMIZE delta.`$tablePath`")
spark.sql(s"OPTIMIZE delta.`$tablePath` WHERE date >= '2023-01-01' AND date < '2023-02-01'")
spark.sql(s"OPTIMIZE delta.`$tablePath` ZORDER BY (id)")
val deltaTable = DeltaTable.forPath(spark, tablePath)
deltaTable.optimize().executeCompaction()
deltaTable.optimize().where("date >= '2023-01-01' AND date < '2023-02-01'").executeCompaction()
deltaTable.optimize().zOrderBy("id").executeCompaction()
spark.stop()
}
}
Configuration et planification de la compaction
Exécution manuelle
Utilisez les scripts ci-dessus pour des optimisations ponctuelles ou déclenchées par des événements.
Compaction planifiée
- Databricks Jobs : exécutez périodiquement des notebooks contenant des requêtes OPTIMIZE
- Apache Airflow : DAG planifié avec tâche SparkSubmit
- Cron job : script shell/Python déclenché via cron (moins robuste)
Exemple DAG Airflow (Python) :
from airflow import DAG
from airflow.operators.spark_submit_operator import SparkSubmitOperator
from datetime import datetime
with DAG(
dag_id="delta_compaction",
schedule_interval="0 3 * * *",
start_date=datetime(2023, 1, 1),
catchup=False,
tags=["delta", "compaction"],
) as dag:
compact_task = SparkSubmitOperator(
task_id="compact_delta_table",
application="/path/to/compaction_script.py",
conn_id="spark_default",
application_args=["/path/to/my_delta_table"],
)
Bonnes pratiques pour la compaction
- Définir la fréquence : dépend du volume d’ingestion, des patterns de requêtes. Exemples : quotidien, hebdomadaire, horaire (cas extrême).
- Z-Ordering ciblé : uniquement si les colonnes ciblées sont utilisées dans les filtres/joins.
- Monitorer l’impact : avant/après (latence, taille fichiers, CPU/mémoire).
- Respecter la rétention : compacter peut fusionner plusieurs versions ; attention au time travel.
- Équilibrer taille/fréquence :
- gros fichiers = meilleures perfs mais compaction coûteuse
- petits fichiers = compaction fréquente mais amélioration limitée
- Auto Compaction (Databricks) : à activer si dispo, mais à monitorer
- Tuning Spark : ajuster
spark.sql.shuffle.partitions
, mémoire, cores - Tests pré-production : toujours valider dans un environnement de test
Débogage de la Data Compaction
- Performances dégradées après compaction : mauvais choix de colonnes pour Z-Ordering, fichiers trop gros
- Problèmes de ressources : compaction = gourmande ; augmenter mémoire, parallélisme ou baisser
maxFileSize
- Durée excessive :
- table énorme
- partitionnement inefficace
- ressources limitées
- taille cible trop faible
- Conflits concurrents : éviter les écritures concurrentes pendant la compaction
- Problèmes Spark : logs à surveiller (mémoire, exécuteurs, erreurs système)
Conclusion
La data compaction est essentielle pour maintenir la performance et maîtriser les coûts dans un environnement Delta Lake. En comprenant son fonctionnement et en appliquant les bonnes pratiques, vous garantissez un système stable, rapide et scalable. Planifiez, surveillez, et testez — c’est la clé pour exploiter au mieux la puissance de OPTIMIZE
.