Retour d’expérience · Qlik Script · MERGE

Mettre à jour un QVD ligne par ligne avec un véritable MERGE

Le MERGE permet d’appliquer au QVD des mouvements précis de type INSERT, UPDATE et DELETE. Il travaille à la ligne et offre une granularité plus fine qu’un DELTA par objet, mais cette précision s’accompagne d’une mécanique plus exigeante côté base et côté Qlik.

1. Le MERGE n’est pas un DELTA « plus performant »

Le DELTA et le MERGE répondent à deux logiques différentes. Un DELTA par objet remplace la version complète d’un objet métier dès qu’une évolution est détectée. Le MERGE descend au niveau de la ligne : il doit savoir précisément quelle ligne a été insérée, modifiée ou supprimée.

Cette granularité ne signifie pas que le MERGE sera automatiquement plus rapide. Les performances dépendent du contexte. Dans mes propres tests, le DELTA s’est souvent montré plus rapide, mais ce résultat reste subjectif et dépend notamment du volume, du nombre de mouvements et du coût des comparaisons en base.

En revanche, le MERGE est clairement plus contraignant à mettre en œuvre : il faut construire les mouvements I/U/D côté base, préserver leur ordre avec une séquence et exécuter la partie Qlik dans le cadre d’un Partial Reload.

À choisir pour la granularité, pas par principe pour la vitesse : le MERGE est pertinent lorsque l’on veut appliquer des changements ligne à ligne et que cette précision justifie la complexité supplémentaire.

2. Le snapshot N-1 est au cœur du MERGE

Le MERGE commence, comme le DELTA, par la comparaison de deux états de la même table. Prenons LIGNES_FACTURE :

TableRôle
LIGNES_FACTUREÉtat courant N de la source
LIGNES_FACTURE_SNAP_N_1État de référence mémorisé à la fin du traitement précédent
LIGNES_FACTURE_MERGEMouvements I/U/D détectés entre N et N-1

La comparaison est effectuée ligne à ligne grâce à ID_LIGNE_FACTURE, qui doit identifier de manière unique et stable la même ligne entre l’état courant, le snapshot et le QVD.

LIGNES_FACTURE
état N
LIGNES_FACTURE_SNAP_N_1
état N-1
LIGNES_FACTURE_MERGE
I / U / D

Le snapshot doit rester inchangé pendant la détection des trois familles de mouvements. Une fois INSERT, UPDATE et DELETE identifiés, il est reconstruit depuis LIGNES_FACTURE afin de devenir la référence du traitement suivant.

3. Construire les mouvements INSERT, UPDATE et DELETE

La table LIGNES_FACTURE_MERGE contient les opérations à appliquer au QVD. Chaque mouvement porte au minimum la clé de la ligne, un TYPE_OPERATION et un ID_DELTA. Pour un INSERT ou un UPDATE, elle contient également les valeurs courantes nécessaires au QVD.

TYPE_OPERATIONID_DELTAID_LIGNE_FACTUREInterprétation
I61001LF-1001Nouvelle ligne
U61002LF-2044Ligne existante modifiée
D61003LF-3098Ligne disparue

3.1 INSERT : présent en N, absent du snapshot

SQL — INSERT
INSERT INTO LIGNES_FACTURE_MERGE
    (TYPE_OPERATION, ID_DELTA, ID_LIGNE_FACTURE,
     PRODUIT, QUANTITE, CA_HT, MARGE)
SELECT 'I',
       SEQ_LIGNES_FACTURE_MERGE.NEXTVAL,
       f.ID_LIGNE_FACTURE,
       f.PRODUIT, f.QUANTITE, f.CA_HT, f.MARGE
FROM LIGNES_FACTURE f
WHERE f.ID_LIGNE_FACTURE IS NOT NULL
  AND NOT EXISTS (
      SELECT 1
      FROM LIGNES_FACTURE_SNAP_N_1 s
      WHERE s.ID_LIGNE_FACTURE = f.ID_LIGNE_FACTURE
  );

3.2 UPDATE : même clé, contenu différent

Pour les lignes présentes dans les deux états, il faut comparer les colonnes métier. L’exemple ci-dessous utilise INTERSECT : si les deux projections sont identiques, l’intersection retourne une ligne. Si une valeur diffère, le NOT EXISTS devient vrai et le mouvement est enregistré comme UPDATE.

SQL — UPDATE
INSERT INTO LIGNES_FACTURE_MERGE
    (TYPE_OPERATION, ID_DELTA, ID_LIGNE_FACTURE,
     PRODUIT, QUANTITE, CA_HT, MARGE)
SELECT 'U',
       SEQ_LIGNES_FACTURE_MERGE.NEXTVAL,
       f.ID_LIGNE_FACTURE,
       f.PRODUIT, f.QUANTITE, f.CA_HT, f.MARGE
FROM LIGNES_FACTURE f
JOIN LIGNES_FACTURE_SNAP_N_1 s
  ON s.ID_LIGNE_FACTURE = f.ID_LIGNE_FACTURE
WHERE NOT EXISTS (
    SELECT f.PRODUIT, f.QUANTITE, f.CA_HT, f.MARGE FROM dual
    INTERSECT
    SELECT s.PRODUIT, s.QUANTITE, s.CA_HT, s.MARGE FROM dual
);

3.3 DELETE : présent dans le snapshot, absent en N

Pour une suppression, le point de départ est nécessairement le snapshot puisque la ligne n’existe plus dans la table courante.

SQL — DELETE
INSERT INTO LIGNES_FACTURE_MERGE
    (TYPE_OPERATION, ID_DELTA, ID_LIGNE_FACTURE,
     PRODUIT, QUANTITE, CA_HT, MARGE)
SELECT 'D',
       SEQ_LIGNES_FACTURE_MERGE.NEXTVAL,
       s.ID_LIGNE_FACTURE,
       s.PRODUIT, s.QUANTITE, s.CA_HT, s.MARGE
FROM LIGNES_FACTURE_SNAP_N_1 s
WHERE NOT EXISTS (
    SELECT 1
    FROM LIGNES_FACTURE f
    WHERE f.ID_LIGNE_FACTURE = s.ID_LIGNE_FACTURE
);

4. Pourquoi une séquence ID_DELTA ?

Les mouvements sont appliqués dans un ordre déterminé. Chaque ligne de LIGNES_FACTURE_MERGE reçoit donc un identifiant séquentiel. Dans cet exemple, les familles sont produites successivement dans l’ordre INSERT, UPDATE puis DELETE.

SQL — séquence
CREATE SEQUENCE SEQ_LIGNES_FACTURE_MERGE
INCREMENT BY 1
MINVALUE 1
NOCACHE;

ID_DELTA sert ensuite de champ de séquence au MERGE ONLY Qlik. Il ne s’agit donc pas d’un simple identifiant technique : il permet de préserver l’ordre des mouvements transmis par la base.

5. Reconstruire le snapshot pour le traitement suivant

La reconstruction du snapshot intervient uniquement après la constitution complète de LIGNES_FACTURE_MERGE. À ce moment, les écarts entre N et N-1 sont mémorisés dans la table de mouvements et l’ancien snapshot peut être remplacé.

SQL — reconstruction du snapshot
DROP TABLE LIGNES_FACTURE_SNAP_N_1 PURGE;

CREATE TABLE LIGNES_FACTURE_SNAP_N_1 NOLOGGING AS
SELECT *
FROM LIGNES_FACTURE
WHERE ID_LIGNE_FACTURE IS NOT NULL;

Sur une table importante, la préparation du snapshot peut également comprendre la création d’un index sur ID_LIGNE_FACTURE et le calcul des statistiques du SGBD. Ce coût fait partie du traitement MERGE côté base et doit être pris en compte lorsque l’on compare cette approche à un DELTA plus simple.

Cycle complet côté base : comparer N / N-1 → produire I/U/D avec leur séquence → reconstruire le snapshot → utiliser ce nouvel état comme N-1 au prochain passage.

6. Côté Qlik : le MERGE s’inscrit dans un Partial Reload

Le QVD existant représente l’état issu du traitement précédent. Il est chargé en mémoire puis les mouvements contenus dans LIGNES_FACTURE_MERGE sont appliqués à cette table. Cette mécanique s’appuie sur le Partial Reload et sur les préfixes adaptés aux chargements concernés.

Qlik Script — charger l’état précédent
[LIGNES_FACTURE]:
REPLACE LOAD *
FROM [lib://QVD_RAW/LIGNES_FACTURE.qvd] (qvd);

Le REPLACE indique que ce LOAD participe au Partial Reload. Cette contrainte est importante : un script MERGE doit être conçu et exploité en tenant compte de ce mode d’exécution, contrairement au DELTA par objet qui peut rester dans une mécanique de chargement plus classique.

7. Comprendre MERGE ONLY

Le cœur du traitement est le préfixe MERGE ONLY. Il reçoit les mouvements et les applique à la table cible en fonction de la clé indiquée après ON.

Qlik Script — MERGE ONLY
MERGE ONLY (ID_DELTA)
ON [ID_LIGNE_FACTURE_Id]
CONCATENATE ([LIGNES_FACTURE])
LOAD
    If(TYPE_OPERATION = 'I', 'Insert',
    If(TYPE_OPERATION = 'U', 'Update',
    If(TYPE_OPERATION = 'D', 'Delete', TYPE_OPERATION))) AS TYPE_OPERATION,
    ID_DELTA,
    ID_LIGNE_FACTURE AS ID_LIGNE_FACTURE_Id,
    PRODUIT,
    QUANTITE,
    CA_HT,
    MARGE;

SQL SELECT
    TYPE_OPERATION,
    ID_DELTA,
    ID_LIGNE_FACTURE,
    PRODUIT,
    QUANTITE,
    CA_HT,
    MARGE
FROM LIGNES_FACTURE_MERGE;

Que signifie chaque partie ?

ÉlémentRôle
MERGE ONLY (ID_DELTA)Applique les mouvements en utilisant ID_DELTA comme séquence.
ON [ID_LIGNE_FACTURE_Id]Indique la clé permettant de retrouver la ligne cible dans le QVD chargé en mémoire.
CONCATENATE ([LIGNES_FACTURE])Désigne la table Qlik sur laquelle les mouvements sont appliqués.
Insert / Update / DeleteActions comprises par le MERGE ; les codes I/U/D venant de la base sont convertis dans le LOAD.

Pour un INSERT, une nouvelle ligne est ajoutée. Pour un UPDATE, la ligne correspondant à la clé est mise à jour avec les valeurs du mouvement. Pour un DELETE, la ligne correspondant à la clé est supprimée de la table en mémoire.

8. Mise en application traditionnelle complète

Une mise en œuvre minimale peut rester entièrement explicite. Il n’est pas nécessaire de disposer d’une SUB générique pour comprendre ou utiliser le mécanisme.

Qlik Script — exemple complet
// 1 - Charger le QVD issu du traitement précédent
[LIGNES_FACTURE]:
REPLACE LOAD *
FROM [lib://QVD_RAW/LIGNES_FACTURE.qvd] (qvd);

// 2 - Appliquer les mouvements détectés côté base
MERGE ONLY (ID_DELTA)
ON [ID_LIGNE_FACTURE_Id]
CONCATENATE ([LIGNES_FACTURE])
LOAD
    If(TYPE_OPERATION = 'I', 'Insert',
    If(TYPE_OPERATION = 'U', 'Update',
    If(TYPE_OPERATION = 'D', 'Delete', TYPE_OPERATION))) AS TYPE_OPERATION,
    ID_DELTA,
    ID_LIGNE_FACTURE AS ID_LIGNE_FACTURE_Id,
    PRODUIT,
    QUANTITE,
    CA_HT,
    MARGE;

SQL SELECT
    TYPE_OPERATION,
    ID_DELTA,
    ID_LIGNE_FACTURE,
    PRODUIT,
    QUANTITE,
    CA_HT,
    MARGE
FROM LIGNES_FACTURE_MERGE;

// 3 - Stocker le nouvel état complet
STORE LIGNES_FACTURE
INTO [lib://QVD_RAW/LIGNES_FACTURE.qvd] (qvd);

Le résultat est un nouvel état complet de LIGNES_FACTURE.qvd : les lignes non modifiées proviennent du QVD précédent, tandis que les mouvements I/U/D ont été appliqués uniquement aux lignes concernées.

9. Les contraintes à garder en tête

Le MERGE est séduisant par sa précision, mais cette précision augmente le nombre de points à maîtriser. La base doit comparer les lignes avec le snapshot, déterminer exactement les I/U/D, alimenter la table de mouvements, gérer la séquence puis reconstruire le snapshot. Côté Qlik, le script dépend du Partial Reload et la clé utilisée par ON doit être parfaitement cohérente avec la clé des mouvements.

Le choix doit donc être fonctionnel et technique. Si remplacer un objet métier complet est peu coûteux, un DELTA peut être plus simple et très performant. Si l’objet est trop volumineux ou si l’on a réellement besoin d’une granularité ligne à ligne, le MERGE devient intéressant malgré ses contraintes supplémentaires.

À retenir

  • Le MERGE compare l’état courant à un snapshot N-1 ligne par ligne.
  • La clé doit être unique et stable entre la source, le snapshot, les mouvements et le QVD.
  • INSERT, UPDATE et DELETE sont construits côté base avant d’être appliqués dans Qlik.
  • ID_DELTA conserve l’ordre des mouvements.
  • Le snapshot est reconstruit seulement après la détection complète des mouvements.
  • MERGE ONLY applique les mouvements à la table Qlik selon la clé indiquée par ON.
  • Le mécanisme impose davantage de contraintes, notamment le Partial Reload et un traitement plus élaboré côté base.
  • Le MERGE n’est pas nécessairement plus rapide qu’un DELTA : il apporte avant tout une granularité plus fine.