Optimieren von DAX-Berechnungen

Abgeschlossen

Wenn performance analyzer eine langsame DAX-Abfrage identifiziert, besteht der nächste Schritt darin, den DAX selbst zu optimieren. Ineffiziente DAX ist eine der häufigsten Ursachen für schlechte Semantikmodellleistung. Kleine Änderungen an Measuredefinitionen können Abfragezeiten erheblich reduzieren.

Verwenden von Variablen zum Entfernen wiederholter Berechnungen

Eine der effektivsten DAX-Optimierungstechniken ist die Verwendung von Variablen (VAR / RETURN). Wenn eine Formel denselben Ausdruck mehrmals auswertet, berechnet das Modul ihn jedes Mal neu. Variablen speichern das Ergebnis eines Ausdrucks einmal und verwenden ihn wieder, wodurch die Abfragezeit ungefähr in der Hälfte für Formeln mit wiederholten Unterausdrücken gekürzt werden kann.

Betrachten Sie dieses Jahreswachstumsmaß:

Sales YoY Growth % =
DIVIDE(
    ([Sales] - CALCULATE([Sales], PARALLELPERIOD('Date'[Date], -12, MONTH))),
    CALCULATE([Sales], PARALLELPERIOD('Date'[Date], -12, MONTH))
)

Der PARALLELPERIOD Ausdruck wird zweimal ausgewertet: einmal im Zähler und einmal im Nenner. Durch das Umschreiben mit einer Variablen wird die Redundanz beseitigt:

Sales YoY Growth % =
VAR SalesPriorYear =
    CALCULATE([Sales], PARALLELPERIOD('Date'[Date], -12, MONTH))
RETURN
    DIVIDE(([Sales] - SalesPriorYear), SalesPriorYear)

Das Ergebnis ist identisch, aber das Modul evaluiert nur einmal SalesPriorYear . Variablen verbessern auch die Lesbarkeit: Beschreibende Variablennamen machen komplexe Formeln einfacher zu verstehen und zu verwalten.

Tipp

Variablen vereinfachen auch das Debuggen. Sie können den RETURN Ausdruck vorübergehend so ändern, dass er nur den Variablenwert ausgibt. Dadurch können Sie Zwischenergebnisse prüfen, ohne die gesamte Formel neu zu schreiben.

Verständnis von FILTER und KEEPFILTERS

Die Anwendung von Filteränderungen in DAX wirkt sich direkt auf die Leistung aus. Die FILTER Funktion durchläuft eine Tabellenzeile nach Zeile, um eine Bedingung auszuwerten. Bei Anwendung auf eine große Tabelle kann diese Iteration teuer sein.

-- Expensive: FILTER iterates the entire Sales table
High Value Sales =
CALCULATE(
    [Total Sales],
    FILTER(Sales, Sales[Amount] > 1000)
)

Wenn Sie FILTER auf einer Tabelle mit Millionen von Zeilen verwenden, erstellt die Engine einen zeilenweisen Iterationskontext. Wenn die Filterlogik nur eine einzelne Spalte umfasst, können Sie häufig durch einen einfacheren booleschen Ausdruck ersetzen FILTER :

-- More efficient: column filter
High Value Sales =
CALCULATE(
    [Total Sales],
    Sales[Amount] > 1000
)

KEEPFILTERS dient einem anderen Zweck. Er behält vorhandenen Filterkontext bei, anstatt ihn zu ersetzen. Verwenden Sie KEEPFILTERS, wenn Sie eine Filterbedingung hinzufügen möchten, ohne die bereits von Datenschnitten oder anderen visuellen Elementen übernommenen außer Kraft zu setzen.

Online Sales =
CALCULATE(
    [Total Sales],
    KEEPFILTERS(Sales[Channel] = "Online")
)

Der Leistungsunterschied zwischen FILTER und direkten Spalten-Prädikaten ist bei großen Tabellen am deutlichsten. Vermeiden Sie als allgemeine Regel FILTER auf ganzen Tabellen, wenn ein Prädikat auf Spaltenebene dasselbe Ergebnis erzielt.

Kosten von Iteratorfunktionen verwalten

Iterator funktioniert wie SUMX, AVERAGEX, MAXX, und COUNTX wertet einen Ausdruck für jede Zeile in einer Tabelle aus und aggregiert dann die Ergebnisse. Sie sind mächtig und manchmal notwendig, aber sie haben einen Kostenaufwand: vor allem auf großen Tischen.

-- Iterates every row in the Sales table
Weighted Average Price =
SUMX(
    Sales,
    Sales[Quantity] * Sales[UnitPrice]
) / SUM(Sales[Quantity])

Diese Formel funktioniert richtig, aber wenn die Tabelle „Verkaufszahlen“ 50 Millionen Zeilen enthält, evaluiert SUMX die Multiplikation für jede Zeile. Wenn ein gleichwertiger Nicht-Iteratorausdruck vorhanden ist, verwenden Sie ihn:

-- Non-iterator equivalent (if LineTotal is a column)
Total Revenue = SUM(Sales[LineTotal])

Iteratorfunktionen sind nicht inhärent schlecht. Sie sind die richtige Wahl, wenn Sie Berechnungslogik auf Zeilenebene benötigen, die nicht mit einer einfachen Aggregation ausgedrückt werden kann. Der Schlüssel ist das Verständnis der Kosten: Iteratorleistung skaliert mit Tabellengröße, sodass ein Iterator über 1.000 Zeilen in Ordnung ist, aber derselbe Iterator über 100 Millionen Zeilen kann zu einem Engpass werden.

Vermeiden sie teure Muster

Bestimmte DAX-Muster sind dafür bekannt, Leistungsprobleme zu verursachen. Wenn Sie sie erkennen, können Sie von Anfang an bessere Formeln schreiben.

COUNTROWS(FILTER(...)) in großen Tabellen. Dieses Muster durchläuft eine ganze Tabelle, um Zeilen zu zählen, die einer Bedingung entsprechen. Ersetzen Sie es durch CALCULATE und COUNTROWS durch ein Filterargument:

-- Expensive
Large Orders = COUNTROWS(FILTER(Sales, Sales[Amount] > 1000))

-- Better
Large Orders = CALCULATE(COUNTROWS(Sales), Sales[Amount] > 1000)

Geschachtelte CALCULATE-Funktion mit komplexen Filtern. Jedes geschachtelte Objekt CALCULATE erstellt einen neuen Filterkontextübergang. Tief geschachtelte Formeln mit mehreren Kontextänderungen sind schwer zu optimieren. Vereinfachen Sie, indem Sie komplexe Maßnahmen in kleinere Komponentenmaßnamen aufteilen, die jeweils eine einzelne Filteränderung behandeln.

Mischen von Aggregationskörnern. Measures, die Daten auf unterschiedlichen Granularitätsebenen kombinieren (z. B. das Vergleichen des Werts einer einzelnen Zeile mit einer Summe auf Tabellenebene) erfordern Kontextübergänge, die teuer sein können. Verwenden Sie Variablen, um die Summe einmal auszuwerten und wiederzuverwenden:

Pct of Total =
VAR TotalSales = CALCULATE([Total Sales], REMOVEFILTERS())
RETURN
    DIVIDE([Total Sales], TotalSales)

Verschieben von Berechnungen auf die Datenebene

Wenn ein DAX-Measure dasselbe Ergebnis für jede Abfrageaktualisierung berechnet und sich die zugrunde liegenden Daten nicht zwischen Aktualisierungen ändern, sollten Sie stattdessen die Materialisierung dieser Berechnung auf der Datenebene in Betracht ziehen.

Zum Beispiel wird eine berechnete Spalte, die Vor- und Nachname verkettet, während der Datenaktualisierung ausgeführt und das Ergebnis speichern. Die gleiche Logik wie eine Metrik würde jedoch für jede Abfrage ausgeführt. Bei statischen Transformationen wie diesem haben Sie zwei Optionen:

  • Power Query berechnete Spalten: Definieren Sie die Transformation in M während des Datenladens. Diese Spalten komprimieren effizienter als berechnete DAX-Spalten, da das VertiPaq-Modul den Speicher während der Last optimieren kann.
  • Berechnungen auf Quellebene: Wenn es sich bei der Datenquelle um eine SQL-Datenbank handelt, fügen Sie die Berechnung der SQL-Ansicht oder -Abfrage hinzu. Dies verwendet die Optimierungsfunktionen des Datenbankmoduls.

Reservieren Sie berechnete DAX-Spalten für Szenarien, die DAX-spezifische Funktionen erfordern, z. B. das Auswerten von Metriken oder die Verwendung von Zeitintelligenz-Funktionen, die von den Beziehungen des Semantikmodells abhängen.

Wichtig

Das Verschieben von Berechnungen nach oben verbessert nicht nur die Abfrageleistung: Es verringert auch die Zeiten für Datenaktualisierungen, da berechnete DAX-Spalten nach dem Laden aller Power Query-Tabellen ausgewertet werden.

Betrachten Sie die KI-Erfahrung

DAX-Leistung wirkt sich direkt auf KI-basierte Erfahrungen aus. In Microsoft Fabric fragen IQ-Daten-Agenten und der Copilot-Chat durch Generierung von DAX-Abfragen im Hintergrund Ihr semantisches Modell ab. Ein Maß, das für einen menschlichen Benutzer fünf Sekunden dauert, dauert für Copilot die gleichen fünf Sekunden: Und KI-Interaktionen weisen häufig engere Timeoutschwellenwerte auf als interaktive Berichte.

Die Optimierung von DAX besteht nicht nur darin, schneller Berichte zu erstellen. Es geht darum, Ihre Daten reaktionsfähig zu machen, um Abfragen in natürlicher Sprache, automatisierte Agents und Echtzeitanalysen zu unterstützen.