📚 Qlik Sense Kurs – Artikel 4 von 28
← Vorheriger Artikel: JOINs vs KEEPs – Wann was verwenden
→ Nächster Artikel: Daten transformieren – String, Math, Date Functions
Mapping Tables vs JOINs – Performance-Optimierung
Was können Sie in 8 Minuten über Mapping Tables vs JOINs lernen?
Wenn Sie ein einzelnes Feld zu einer großen Tabelle hinzufügen müssen, ist ein `LEFT JOIN` oft langsam und ineffizient. Dieser Guide stellt Ihnen die `ApplyMap`-Funktion vor – eine extrem schnelle Alternative, die Ihre Skript-Laufzeiten drastisch verkürzen kann.
- `ApplyMap()` für blitzschnelle 1:1-Lookups implementieren (oft 10-100x schneller als ein `LEFT JOIN`).
- Multi-Level-Lookups für hierarchische Daten erstellen (z.B. Kunde → Region → Land).
- Eine fundierte, performance-kritische Entscheidung treffen: Wann `ApplyMap` und wann doch ein `JOIN` die bessere Wahl ist.
Zeitinvestition: 8 Min Lesen + 45 Min Hands-on
Voraussetzung: JOINs vs KEEPs verstanden
Quick Win: In 3 Minuten den ersten `ApplyMap`-Befehl implementieren
Wie starte ich meinen ersten ApplyMap schnell?
Das Problem: Sie haben eine Faktentabelle mit 1 Million Bestellungen (`Orders`) und müssen für jede Bestellung den `CustomerName` aus einer Dimensionstabelle (`Customers`) hinzufügen.
Die Lösung mit `ApplyMap` in 2 Schritten:
- Erstellen Sie ein temporäres «Wörterbuch» (eine Mapping-Tabelle) mit `MAPPING LOAD`.
- Wenden Sie dieses Wörterbuch mit der `ApplyMap()`-Funktion beim Laden der Faktentabelle an.
Schritt 1: Das «Wörterbuch» erstellen
Eine `MAPPING LOAD`-Tabelle ist keine normale Qlik-Tabelle. Es ist eine hochoptimierte, temporäre Key-Value-Struktur, die nur während des Skriptlaufs existiert und danach automatisch gelöscht wird. Sie muss **exakt zwei Spalten** haben: den Schlüssel (Key) und den Wert (Value).
CustomerNameMap:
MAPPING LOAD
CustomerID,
CustomerName
FROM [lib://DataFiles/customers.csv]
(txt, utf8, embedded labels, delimiter is ';');
Schritt 2: Das «Wörterbuch» anwenden
Beim Laden der `Orders`-Tabelle nutzen wir `ApplyMap()`, um für jede `CustomerID` den entsprechenden Namen nachzuschlagen.
Orders:
LOAD
OrderID,
CustomerID,
OrderDate,
Amount,
ApplyMap('CustomerNameMap', CustomerID, 'Unknown Customer') as CustomerName
FROM [lib://DataFiles/orders.csv]
(txt, utf8, embedded labels, delimiter is ';');
Was hier passiert:
- `ApplyMap(‚MapName‘, Key, Default)`:
- `’CustomerNameMap’`: Der Name unseres zuvor erstellten Wörterbuchs.
- `CustomerID`: Der Schlüssel aus der `Orders`-Tabelle, den wir nachschlagen.
- `’Unknown Customer’`: Ein extrem wichtiger Fallback-Wert, falls ein Schlüssel nicht gefunden wird.
- Performance-Vorteil: `ApplyMap` nutzt einen direkten **Hash-Lookup**, was deutlich schneller ist als die komplexen, zeilenbasierten Vergleiche eines `JOIN`. Bei 1 Mio. Zeilen kann der Unterschied von ~45 Sekunden (`JOIN`) auf ~8 Sekunden (`ApplyMap`) enorm sein.
Checkpoint: Sehen Sie die neue Spalte `CustomerName` in Ihrer `Orders`-Tabelle? Erfolg! Werden nur `NULL`-Werte oder der Default-Wert angezeigt? Springen Sie zum Abschnitt Troubleshooting.
Was ist der Unterschied zwischen ApplyMap, JOIN und IntervalMatch?
Wählen Sie die richtige Methode basierend auf dem Anwendungsfall. Jede Technik hat ihre Berechtigung.
| Methode | Beziehung | Performance | Ideal für… |
|---|---|---|---|
| ApplyMap | 1:1 | 🚀 Sehr schnell | Das Hinzufügen von einem einzelnen Feld zu einer großen Tabelle (z.B. Name, Kategorie, Status). Der Performance-Champion. |
| LEFT JOIN | 1:1, 1:N | 🐢 Langsam | Das Hinzufügen von mehreren Feldern aus einer Dimensionstabelle. Flexibler, aber deutlich langsamer. |
| IntervalMatch | Zeiträume | 💨 Mittel | Die Zuordnung von Ereignissen zu Zeiträumen (z.B. eine Transaktion zu einer Preisperiode). Ein Spezialfall, den `ApplyMap` und `JOIN` nicht lösen können. |
| WHERE EXISTS | Filter | 🚀 Sehr schnell | Das reine Filtern einer Tabelle basierend auf den Schlüsseln einer anderen, ohne Daten hinzuzufügen. |
Was ist ein Deep-Dive in ApplyMap() und wie vergleicht es sich mit JOINs?
Wie versteht man Syntax und Parameter in Mapping Tables vs JOINs?
Der zweite Parameter der `ApplyMap()`-Funktion kann nicht nur ein Feldname, sondern ein beliebiger Ausdruck sein. Dies ermöglicht dynamische Lookups.
Hier erstellen wir eine Map, deren Wert aus Name und Region zusammengesetzt wird.
CustomerMap:
MAPPING LOAD
CustomerID,
CustomerName & ' (' & Region & ')' as CustomerInfo
FROM customers.csv;
Orders:
LOAD
OrderID,
CustomerID,
ApplyMap('CustomerMap', CustomerID, 'Unknown') as CustomerInfo,
ApplyMap('CustomerMap', 'CUST_' & CustomerID, 'Not Found') as AltCustomerInfo,
ApplyMap('CustomerMap', CustomerID) as CustomerInfoOptional
FROM orders.csv;
Was sind Multi-Level Lookups und wie unterscheiden sie sich von JOINs?
Für hierarchische Abhängigkeiten (Kunde → Region → Land) können Sie `ApplyMap()`-Aufrufe verschachteln. Die Verarbeitung erfolgt von innen nach außen: Das Ergebnis des inneren Aufrufs wird zum Schlüssel des äußeren Aufrufs.
Zuerst erstellen wir die notwendigen Mapping-Tabellen für jede Hierarchiestufe.
CustomerRegionMap:
MAPPING LOAD CustomerID, RegionID FROM customers.csv;
RegionCountryMap:
MAPPING LOAD RegionID, CountryName FROM regions.csv;
CountryContinentMap:
MAPPING LOAD CountryName, ContinentName FROM countries.csv;
Dann wenden wir die Maps in verschachtelter Form an, um die gesamte Hierarchie aufzulösen.
Orders:
LOAD
OrderID, CustomerID, Amount,
ApplyMap('CustomerRegionMap', CustomerID, 'UNKNOWN') as RegionID,
ApplyMap('RegionCountryMap',
ApplyMap('CustomerRegionMap', CustomerID, 'UNKNOWN'),
'Unknown Country') as CountryName,
ApplyMap('CountryContinentMap',
ApplyMap('RegionCountryMap',
ApplyMap('CustomerRegionMap', CustomerID, 'UNKNOWN'),
'Unknown Country'),
'Unknown Continent') as ContinentName
FROM orders.csv;
Hinweis: Bei mehr als zwei oder drei Ebenen wird dieser Ansatz schnell unlesbar und schwer zu debuggen. In solchen Fällen ist oft ein mehrstufiger `RESIDENT`-Load die sauberere Lösung.
Wie kann ich die MAPPING LOAD Optimierung durchführen?
Wie erstelle ich effizient Mapping-Tabellen?
Die Performance hängt stark von der Größe Ihrer Mapping-Tabelle ab. Laden Sie nur, was Sie wirklich brauchen.
- Schlecht: Lädt alle Spalten und Zeilen, obwohl nur zwei Spalten benötigt werden.
- Besser: Filtert die Daten mit `WHERE`, bevor die Map erstellt wird. Dies reduziert die Map-Größe und spart Speicher.
- Optimal: Bereinigt die Schlüssel (`Trim`, `Upper`) direkt beim Laden. Dies verhindert Fehler und spart Rechenleistung bei der späteren Anwendung.
BadMap:
MAPPING LOAD CustomerID, CustomerName FROM customers.csv;
GoodMap:
MAPPING LOAD CustomerID, CustomerName FROM customers.csv
WHERE Status = 'Active';
OptimalMap:
MAPPING LOAD
Trim(Upper(CustomerID)) as CustomerID,
CustomerName
FROM customers.csv
WHERE Status = 'Active';
Wie funktioniert Cached Mapping für wiederholte Verwendung?
Wenn sich die Quelldaten für Ihre Map selten ändern, können Sie diese als QVD zwischenspeichern. Das Skript prüft, ob die QVD existiert und lädt sie, anstatt die Map bei jedem Durchlauf neu aus der Quelle zu erstellen.
IF FileSize('lib://Cache/CustomerMap.qvd') > 0 THEN
CustomerMapData:
LOAD * FROM [lib://Cache/CustomerMap.qvd] (qvd);
ELSE
CustomerMapData:
LOAD CustomerID, CustomerName FROM customers.csv WHERE Status = 'Active';
STORE CustomerMapData INTO [lib://Cache/CustomerMap.qvd] (qvd);
END IF
CustomerMap:
MAPPING LOAD * RESIDENT CustomerMapData;
DROP TABLE CustomerMapData;
Wie kann man ApplyMap für Datenqualität nutzen?
`ApplyMap` ist eine extrem schnelle Methode, um Daten zu validieren oder zu standardisieren.
Hier erstellen wir eine Validierungs-Map, die nur gültige Kunden enthält. In einem zweiten Schritt nutzen wir eine Standardisierungs-Map, um unterschiedliche Schreibweisen für Länder zu vereinheitlichen.
ValidCustomersMap:
MAPPING LOAD
CustomerID,
'VALID' as Status
FROM customers.csv
WHERE Status = 'Active' AND Len(CustomerName) > 0;
CountryStandardMap:
MAPPING LOAD Old, New INLINE [
Old, New
"Deutschland", "Germany"
"UK", "United Kingdom"
"USA", "United States"
];
Orders:
LOAD
OrderID, CustomerID, Country, Amount,
ApplyMap('ValidCustomersMap', CustomerID, 'INVALID') as CustomerValidation,
ApplyMap('CountryStandardMap', Country, Country) as StandardCountry
FROM orders.csv;
Wie behebt man häufige Probleme bei Mapping Tables vs JOINs?
Warum gibt ApplyMap immer den Default-Wert zurück?
Problem: Die Funktion findet keine Übereinstimmungen. Dies liegt fast immer daran, dass die Schlüssel nicht exakt übereinstimmen.
Checkliste zur Lösung:
- Datentyp-Konflikt (Zahl vs. Text): Die `CustomerID` `123` ist nicht dasselbe wie `’123’`. Sorgen Sie für Konsistenz, z.B. mit `Num(CustomerID)`.
- Unsichtbare Leerzeichen: Der Wert `’CUST01 ‚` ist nicht dasselbe wie `’CUST01’`. Verwenden Sie `Trim()` auf beiden Seiten.
- Groß-/Kleinschreibung: Der Wert `’cust01’` ist nicht dasselbe wie `’CUST01’`. Verwenden Sie `Upper()` auf beiden Seiten.
Am besten bereinigen Sie die Schlüssel immer präventiv direkt im `MAPPING LOAD`.
Warum ist die Performance schlechter als erwartet bei Mapping Tables vs JOINs?
Problem: Ihr `ApplyMap` ist nicht so schnell wie erhofft.
Ursache: Dies passiert meist, wenn die Mapping-Tabelle selbst extrem groß ist (z.B. > 5-10 Mio. Zeilen). `ApplyMap` ist für Lookups in «kleinen» bis «mittelgroßen» Dimensionen optimiert. Wenn Ihre «Dimension» riesig ist, kann ein `LEFT JOIN` unter Umständen performanter sein, da die Qlik Engine ihn anders optimiert.
Mit diesem Muster können Sie die Strategie basierend auf der Größe der Lookup-Tabelle dynamisch anpassen.
LookupSizeCheck:
LOAD Count(*) as LookupSize FROM customers.csv;
LET vLookupSize = Peek('LookupSize', 0, 'LookupSizeCheck');
DROP TABLE LookupSizeCheck;
IF $(vLookupSize) < 5000000 THEN
CustomerMap:
MAPPING LOAD CustomerID, CustomerName FROM customers.csv;
Orders:
LOAD *, ApplyMap('CustomerMap', CustomerID, 'Unknown') as CustomerName
FROM orders.csv;
ELSE
Customers:
LOAD CustomerID, CustomerName FROM customers.csv;
Orders:
LOAD * FROM orders.csv;
LEFT JOIN (Orders)
LOAD CustomerID, CustomerName RESIDENT Customers;
DROP TABLE Customers;
END IF
Was sind die nächsten Schritte im Kurs zu Mapping Tables vs JOINs?
Als nächstes: Daten transformieren – String, Math, Date Functions
Verwandte Themen: