Tableaus Datenmodell im Umgang mit multiplen Faktentabellen und Shared Dimensions
Seit der Version 2020.2 ist das Relationen-Datenmodell Bestandteil des Tableau Desktop und erlaubt es, neben klassischen Joins nun auch Beziehungen zwischen Tabellen zu bilden. Dies ermöglicht vor allem flexiblere Auswertungen mit unterschiedlichsten Granularitäten innerhalb Tableaus ohne die Verwendung von Detailgenauigkeitsausdrücken (LoD / Level of Detail-Formeln).
Erstellt man sich eine eigene Tableau Datenquelle im Relationen-Modell, umfasst diese in vielen Fällen Fakten- und Dimensionstabellen, die miteinander verknüpft werden sollen. Liegen hierbei mehr als eine Dimensionstabelle vor, die mit mehreren unterschiedlichen Faktentabellen verknüpft werden sollen, kommt schnell die Frage nach der optimalen Modellierung im Relationen-Modell auf.

Grundsätzlich lässt sich dieser beschriebene Fall auch im klassischen Modell (physischen Layer) mit Joins darstellen, solange die Faktentabellen die gleiche Granularität aufweisen. Andernfalls ist die Verwendung von LoDs notwendig. Doch gerade um letzteres zu vermeiden, ist eine Lösung im Relationen-Modell wünschenswert. Die Modellierung mit mehreren Faktentabellen, die wiederum mit mehreren gemeinsamen Dimensionstabellen (Shared Dimensions) verknüpft werden, wird jedoch nicht unterstützt.[1] Das heißt eine 1:1 Modellierung, wie in Abb. 1 dargestellt, ist nicht möglich. Warum? Die Ursache hierin liegt in dem Festlegen von nur einer Basistabelle(siehe Abb.2: Dimension 1), die als erste im logischen Layer platziert wird und dem damit nicht möglichen Bilden von Circular Relationships.[2] [3]

Eigentlich wäre es also notwendig, von einer Entität - entweder den Fakten oder den Dimensionen – aus, zwei Relationen nach links auszuprägen. Genau dies ist aber im Relationen-Modell nicht möglich.
Oft wird dieses Problem umgangen, in dem die Dimensionen innerhalb der Faktentabelle integriert werden, sodass nur die Faktentabellen miteinander verknüpft werden müssen und folgendes Relationen-Modell resultiert:

Jedoch gilt dies als problematisch, wenn nicht eine Faktentabelle die Obermenge an gemeinsamen Dimensionen hat, bzw. die Tabellen viele unterschiedliche Dimensionsausprägungen haben [4]. Dies würde dazu führen, dass für jede geteilte Dimension eine IFNULL Berechnung erstellt werden müsste, um abzufragen, ob die Ausprägung nur in Fakt 1 oder nur in Fakt 2 auftritt. Welche Alternativen gibt es hierzu?
Lösungsansatz
Wie bereits beschrieben, lässt sich nur eine logische Tabelle im Relationen-Modell als Basistabelle definieren. Der Ansatz, der in diesem Artikel untersucht wird, berücksichtigt deshalb alle Dimensionen innerhalb einer einzigen logischen Tabelle und setzt diese in Relation zu den Fakten.

Wie lässt sich dieser Ansatz mittels verschiedener Wege in Tableau realisieren und welcher verspricht - auch im Vergleich mit den klassischen LoDs - möglichst wenige Einschnitte in der Performance?
Datenbasis
Zur Generierung eines Beispieldatensatzes wurde das Data Prep Tool Alteryx Designer verwendet.

Der Datensatz umfasst drei Dimensionstabellen sowie zwei Faktentabellen, die alle in csv-Dateien gespeichert wurden.
Tabelle |
Anzahl Datensätze |
Dim_Produkt |
1.600 |
Dim_Kunde |
1.200 |
Dim_Zeit |
365 |
Fakt_Ist |
140.160.000 |
Fakt_Plan |
38.400 |
Die beiden Faktentabellen weisen unterschiedliche Granularitäten auf, da die Daten aus Fakt_Ist auf der Basis von Kunden und die der Fakt_Plan hingegen auf Basis der aggregierten Kundenkategorie vorliegen:

Somit unterscheiden sich beide Faktentabellen in ihrer Beziehung zur Kundenhierarchie. Für die anderen beiden Dimensionen (Produkt und Datum) gelten sowohl für Fakt_Ist als auch Fakt_Plan die gleiche Granularität in den Join-Kriterien.
In Hinblick auf die referentielle Integrität weisen alle Dimensionen aus den Faktentabellen ein Gegenstück in den Dimensionstabellen auf. Jedoch liegen nicht zwangsläufig alle möglichen Dimensionselemente in den Fakten vor.
Die im Eingang benannte Problemstellung lässt sich somit mit den generierten Daten nachbilden. Wie bereits beschrieben, kann dabei nicht jede Tabelle eine eigene logische Tabelle im Layer darstellen, da die Verknüpfungen so nicht richtig gebildet werden könnten. Ziel ist es daher, eine einzige logische Tabelle zu definieren, die sich aus allen geteilten Dimensionen zusammensetzt.
Welche Modellierungsmöglichkeiten bestehen hierfür in Tableau?
Modellierung
Bei der Modellierung der Datenquelle in Tableau wurden drei unterschiedliche Vorgehen im Vergleich verprobt: zwei verschiedene Varianten des beschriebenen Lösungsansatzes über einen Cross Join aller geteilten Dimensionen sowie zur Gegenüberstellung eine Variante mit der Verwendung von LoDs. Ein Cross Join kombiniert dabei sämtliche Elemente aller Dimensionen miteinander, ungeachtet dessen, ob diese Kombinationen in den Fakten vorkommen oder nicht.
1. Cross Join aller Dimensionen innerhalb einer logischen Tabelle
In diesem Ansatz werden alle Ausprägungen der Dimensionstabellen in einer logischen Tabelle mit einem Cross Join zusammengeführt.
Tableau bietet keine Möglichkeit, einen Cross Join direkt im physischen Layer anzulegen. Technisch erfolgt dieser aber, sobald ein Join-Kriterium gewählt wird, dass zwangsläufig immer erfüllt ist. Hier wurde daher das Kriterium 1=1 gewählt. Aus diesem Kreuzprodukt resultiert eine Datenmenge von ca. 700 Mio. Zeilen. Die mit dem Cross Join definierte logische Tabelle ‚Dim (CrossJoin)‘ wird unter Berücksichtigung der Kardinalität und referentiellen Integriät im logischen Layer mit den beiden Faktentabellen verbunden.
2. Cross Join bereits in Datensatz durchgeführt (All_Dim)
Diese Variante unterscheidet sich lediglich vom ersten Ansatz darin, dass der Cross Join bereits im Vorfeld durchgeführt wurde und eine physische Gesamttabelle mit den knapp 700 Mio. Einträgen vorliegt. Somit wird die logische Tabelle in diesem Fall mit nur einer csv-Datei definiert:
Auch diese wird wieder im logischen Layer, analog zum ersten Ansatz, mit den Faktentabellen verbunden.
3. Bilden von LoD Berechnungen für die Kennzahlen (LoD)
Im Vergleich zu den dargestellten Ansätzen wird ebenso der alternative Weg ohne Verwendung des Relationen-Modells untersucht. Hierbei werden alle relevanten Dimensions- und Faktentabellen im physischen Layer miteinander gejoint (Plan ist auch mit Dim_Zeit und Dim_Produkt verbunden, wird von Tableau aber nicht dargestellt).
Somit liegt nur eine logische Tabelle vor, die nicht in Beziehung zu anderen steht:
Die Werte aus der Plan Faktentabelle werden durch die Verknüpfung im physischen Layer vervielfacht, da innerhalb einer Kundenkategorie (Join-Kriterium für Fakt_Plan) mehrere Kunden auftreten können. Um nicht Duplikate dieser Art in die Summenbildung der Kennzahl einfließen zu lassen, wird ein berechnetes Feld erstellt, welches die Granularität berücksichtigt.
Extrakte
Für alle beschriebenen Modellierungsvarianten wurden neben der Verwendung von Live- Verbindungen zu den csv_Dateien auch Extrakte erstellt und ausgewertet. Bei der Erstellung der Extrakte kann festgelegt werden, ob die Extrakt-Tabellen auf Basis der logischen oder physischen Tabellen im Datenmodell erstellt werden sollen.
Im Beispiel der Cross Join-Variante würde ein Extrakt als logische Tabelle erst alle Dimensionen miteinander verknüpfen und anschließend als eine flache Extrakt-Tabelle speichern, während der Extrakt als physische Tabelle alle Dimensionstabellen als eigene Tabellen speichert. Die Faktentabellen werden in beiden Fällen separat erstellt.
Für die Auswertung wurden beide Auswahlmöglichkeiten getestet. Lediglich für die Variante All_Dim (im Vorfeld durchgeführter Cross Join) ist bei der Erstellung des Extrakts nur die Speicherung als logische Tabellen möglich, da keine physischen Verknüpfungen innerhalb der logischen Tabellen durchgeführt werden.
Hieraus resultieren somit in Summe acht getestete Tableau Datenquellen:
Modell |
Verbindung |
Cross Join (in einer logischen Tabelle)
|
Live |
Extrakt (als physische Tabellen, phy) |
|
Extrakt (als logische Tabellen, log) |
|
All_Dim (vorab gebildeter Join aller Dimensionen) |
Live |
Extrakt (als logische Tabellen, log) |
|
LoD |
Live |
Extrakt (als physische Tabellen, phy) |
|
Extrakt (als logische Tabellen, log) |
Tests / Ergebnisse
Als einheitlicher Testfall wurde für jede Datenquelle die gleiche Visualisierung erstellt und die Performance mittels Leistungsaufzeichnung über mehrere Zyklen erfasst. Der Cache wurde hierbei nach jedem Durchlauf geleert. Um sicherzustellen, dass in der Abfrage stets alle Tabellen im jeweiligen Modell abgefragt werden, wurden für den Testfall alle Hierarchien aus den Dimensionstabellen und die Kennzahlen aus den Faktentabellen verwendet.
Im Fokus der Auswertung liegt vor allem die durchschnittliche Gesamtdauer aller Execution Queries (also die Zeit, die Tableau auf die Ausführung des Daten-SQLs wartet). Grundsätzlich lässt sich festhalten, dass Tableau für den Testfall drei Execution Queries generiert (jeweils eine für Ist- Kennzahl Berechnung, Plan-Kennzahl Berechnung und alle Dimensionen). Eine Ausnahme stellt hierbei das LoD Modell dar, welches zur Bestimmung aller Inhalte lediglich eine Query benötigt.
- Extrakte bilden führt nicht zwangsläufig zu verkürzten Execution Queries
Mit Blick auf die durchschnittliche Gesamtdauer der Execution Queries über alle Testfälle zeigt sich, dass die Erstellung eines Extraktes nicht gleichbedeutend mit verkürzten Execution Queries sein muss: In den Modellierungen ‚Cross Join‘ und ‚All_Dim‘ können sogar bei Speicherung auf logischen Tabellen im Vergleich zur Live-Verbindung längere Execution Times festgestellt werden.
- Performance ist nicht mit Execution Time gleichzusetzen
Ein anderer wichtiger Aspekt hierbei ist, dass Tableau bei jeder Abfrage das passende SQL Statement generiert (Compile Queries). Insbesondere bei den letztgenannten Live-Modellen ist aufgefallen, dass die Compile Queries die Execution Queries weit überschritten (die Compile Queries sind in Abbildung 16 vernachlässigt, um andere Größen besser vergleichen zu können). Um ein verlängertes Laden beim initialen Öffnen einer Arbeitsmappe oder beim Aktualisieren der Datenquelle mit vergleichbarem Datensatz zu vermeiden, kann die Verwendung eines Extraktes somit auch in vermeintlich längeren Varianten sinnvoll und hilfreich sein. Bei der Modellierung mit LoDs kann eine leichte Verkürzung der Execution Query durch die Verwendung beider Extraktvarianten ermittelt werden.
- csv-Live Verbindungen sind im Testfall gleich schnell
Generell ist im Bereich der Live-Verbindungen hinsichtlich der durchschnittlichen Execution Query-Gesamtdauer kein wesentlicher Unterschied zwischen den unterschiedlichen Modellierungen feststellbar (~35s). Wobei hier fairerweise festzuhalten ist, dass das Reporting auf csv-Dateien dieser Größe grundsätzlich nicht performant sein kann und hier relationale, indexbasierte Datenbanken sich anders geben können.
- Schnellste Verarbeitung mit Cross Join im physischen Layer und Extrakt auf physischen Tabellen
Im Gesamtvergleich stellt sich eine Modellierungsform für den durchgeführten Testfall als besonders performant dar: Das Bilden eines Cross Joins aller Dimensionstabellen innerhalb einer logischen Tabelle einschließlich der Speicherung des Extrakts auf physische Tabellen. Das heißt, alle Dimensionen werden innerhalb des Extrakts als separate Tabelle gespeichert und erst in den Abfragen miteinander verknüpft. Auch der Blick im Vergleich auf die Werte von ‚All_Dim Extract (log)‘ und ‚Cross Extract (log)‘ lässt darauf schließen, dass Tableaus Hyper Engine schnellere Abfragen durchführt, wenn die Dimensionstabellen separat voneinander gespeichert sind, anstatt vorab in einer großen Tabelle zusammengeführt werden.
Schaut man sich nun einen Vergleich der Live-Version und des besonders performanten Extrakts nach den einzelnen Execution Queries an (wie oben beschrieben werden drei generiert), lässt sich erkennen, dass die Dauer der Kennzahlenberechnungen im Schnitt kaum voneinander abweicht.
Jedoch führt der auf physische Tabellen verteilte Extrakt dazu, dass alle im Testfall verwendeten Dimensionen wesentlich schneller abgefragt werden können und somit daraus ein immenser Performance-Gewinn resultiert.
Zusammenfassung / Empfehlung
In Tableaus 2020.2 Version releastem neuen Relationen-Modell stellt es sich häufig als herausfordernd dar, eine Datenquelle zu bauen, die mehrere Faktentabellen enthält, die sich dieselben Dimensionstabellen teilen (Multiple Factsheets with shared Dimensions). Als Lösungsansatz wurde hierbei eine logische Tabelle verwendet, die alle Dimensionsausprägungen durch einen physischen Cross Join enthält und mit den Faktentabellen logisch verknüpft wurde.
Im Rahmen von einem definierten Testfall konnte gezeigt werden, dass die Modellierung, in der alle Dimensionstabellen separat voneinander vorliegen und erst in Tableau miteinander gejoint werden, die schnellsten Abfragezeiten erzielen konnte. Als Vergleich wurde hierbei eine Variante analysiert, die den Cross Join aller Dimensionen vorab berechnet hatte (als eine große Gesamttabelle) sowie eine klassische Modellierung mit Hilfe von LoDs.
Im Zusammenhang mit der Verwendung eines Extrakts, der die Tabellen auf physische Tabellen speichert, konnte gezeigt werden, dass es für Tabeaus Hyper Engine vorteilhaft ist, erst in der Abfrage mehrere Tabellen miteinander zu joinen als eine große, flache Tabelle einzulesen, die bereits alle Ausprägungen enthält.
Auf Basis des Testfalls ist somit für das Modell mit mehreren Faktentabellen, die mit denselben Dimensionstabellen verknüpft werden sollen, zu empfehlen, die Dimensionstabellen separat voneinander zu speichern und erst in Tableau miteinander zu joinen. Dieser Cross Join definiert im Relationen-Modell eine logische Tabelle, die unter Berücksichtigung der Kardinalität mit den Faktentabellen verbunden und dann in einen Extrakt überführt werden kann.
Quellen:
[1] https://help.tableau.com/current/pro/desktop/en-us/relate_tables.htm
[2] https://help.tableau.com/current/pro/desktop/en-us/relate_tables.htm
[3] https://help.tableau.com/current/pro/desktop/en-us/datasource_datamodel.htm
[4] https://help.tableau.com/current/online/de-de/datasource_datamodel.htm
