Das ultimative Power BI Cheatsheet als Advanced Developer

Power BI Golden Rules — 34 Regeln, die den Unterschied zwischen Prototyp und Produktion ausmachen.

Von · ~15 Min. Lesezeit · Level: Advanced
Data-Dashboard mit Charts und KPIs auf einem Laptop-Bildschirm – Symbolbild für Power BI Development
Photo: Carlos Muza / Unsplash

Das ausführliche Companion-Dokument zum „Power BI Golden Rules"-Cheatsheet. 34 Regeln, vier Domänen, null Kaffeepausen. Für alle, die Power BI über den Prototypen-Status hinaus produktiv entwickeln.

Warum dieser Guide?

Jeder, der Power BI über den Prototypen-Status hinaus entwickelt hat, kennt die Realität: Ein Modell, das im Desktop butterweich läuft, stolpert im Service über 10 Millionen Zeilen. Ein Bericht, den das Management „eigentlich ganz schick" findet, wird trotzdem nicht genutzt, weil niemand den Key Insight findet. Eine Measure, die der Werkstudent gebaut hat, killt nach sechs Monaten die Performance, weil sie bei jedem Filterwechsel die ganze Fact-Table scannt.

Die Ursache ist fast nie „Power BI ist zu langsam". Die Ursache sind handwerkliche Entscheidungen, die früh im Entwicklungsprozess getroffen — oder eben nicht getroffen — wurden.

Die folgenden 34 Regeln sind das Destillat aus hunderten Developer-Stunden in produktiven Power-BI-Projekten. Sortiert nach den vier Domänen, in denen fortgeschrittene Entwickler die meiste Zeit verbringen: DAX & Performance, Data Modeling, Power Query und Visualisierung. Jede Regel hat einen kurzen „Warum" — und wo es sinnvoll ist, ein konkretes Code-Snippet, das du direkt in dein Projekt übernehmen kannst.

Dieser Guide richtet sich nicht an Einsteiger. Wenn du weißt, was CALCULATE macht, schon mal ein Star Schema gebaut hast und M-Code nicht aussieht wie eine fremde Sprache, bist du richtig. Ziel: dass du nach der Lektüre mindestens drei Dinge an deinem aktuellen Modell anders machst.

Daten sind nur dann wertvoll, wenn sie Entscheidungen besser machen — und Power-BI-Modelle nur dann wartbar, wenn sie handwerklich sauber gebaut sind.

DAX & Performance — 9 Regeln

Code auf einem Bildschirm in Dunkelmodus – Symbolbild für DAX-Entwicklung und Performance-Optimierung
Photo: Florian Olivo / Unsplash

Hier entscheidet sich, ob ein Report in 200 Millisekunden oder in 20 Sekunden rendert. DAX ist unbarmherzig: die Engine verzeiht viele Designfehler — aber Performance bekommst du nur, wenn du weißt, was unter der Haube passiert.

01SUMMARIZECOLUMNS statt SUMMARIZE

SUMMARIZE mit CALCULATE darin ist ein Klassiker aus der DAX-Steinzeit — und sollte genau dort bleiben. SUMMARIZECOLUMNS ist die von Microsoft bevorzugte Funktion für Gruppierungen mit Aggregaten: die Storage Engine generiert einen wesentlich effizienteren Plan, mit weniger Materialisierungen, weniger Callbacks in die Formula Engine und drastisch kürzerer Laufzeit bei großen Datasets.

-- AVOID
SUMMARIZE(
    Sales,
    'Date'[Year],
    "Revenue", CALCULATE(SUM(Sales[Amount]))
)

-- DO
SUMMARIZECOLUMNS(
    'Date'[Year],
    "Revenue", SUM(Sales[Amount])
)

Die einzigen legitimen Einsatzgebiete für SUMMARIZE sind reine Spalten-Projektionen ohne Aggregation — und selbst da gibt es meist elegantere Alternativen.

02VAR für Wiederverwendung

Variablen sind nicht nur syntaktischer Zucker. Jede VAR wird genau einmal evaluiert — unabhängig davon, wie oft sie im RETURN-Teil referenziert wird. Wer denselben Ausdruck zweimal hinschreibt, bezahlt zweimal die volle Evaluation, inklusive aller Filter-Kontextwechsel und Storage-Engine-Queries.

-- AVOID
Revenue YoY % =
DIVIDE(
    SUM(Sales[Amount]) - CALCULATE(SUM(Sales[Amount]), SAMEPERIODLASTYEAR('Date'[Date])),
    CALCULATE(SUM(Sales[Amount]), SAMEPERIODLASTYEAR('Date'[Date]))
)

-- DO
Revenue YoY % =
VAR CurrentRevenue = SUM(Sales[Amount])
VAR PriorRevenue   = CALCULATE(SUM(Sales[Amount]), SAMEPERIODLASTYEAR('Date'[Date]))
RETURN DIVIDE(CurrentRevenue - PriorRevenue, PriorRevenue)

Zusätzlicher Benefit: Variablen frieren den Filter-Kontext zum Zeitpunkt ihrer Definition ein. Komplexe Measures werden nicht nur schneller, sondern auch semantisch eindeutig — du vermeidest Context-Transition-Überraschungen, die sich sonst hartnäckig in Produktion einschleichen.

03Früh filtern, spät aggregieren

Die VertiPaq-Engine liebt kleine Zwischenergebnisse. Jede Operation, die die Zeilenzahl reduziert, bevor aggregiert wird, spart Speicher, Callbacks und Zeit. Das gilt für CALCULATE-Filter wie für iterierende Funktionen (SUMX, FILTER).

-- AVOID: erst alle Zeilen iterieren, dann filtern
SUMX(
    FILTER(Sales, Sales[Region] = "DACH"),
    Sales[Amount] * Sales[FXRate]
)

-- DO: Filter als CALCULATE-Modifier, SUMX nur noch auf Subset
CALCULATE(
    SUMX(Sales, Sales[Amount] * Sales[FXRate]),
    Sales[Region] = "DACH"
)

Merksatz: Filter gehören so nah wie möglich an die Datenquelle — im Semantikmodell idealerweise auf die Dimensionstabelle, im Power Query so früh wie möglich in der Pipeline.

04SWITCH statt IF-Ketten

Verschachtelte IF-Anweisungen sind Wartungshölle und kosten Kompilierzeit. SWITCH(TRUE(), …) ist nicht nur lesbarer, sondern kompiliert zu einem schlankeren Abfrageplan. Bei fünf oder mehr Bedingungen merkst du den Unterschied spürbar — bei zehn wird er dramatisch.

-- AVOID
Band =
IF(Sales[Amount] < 100, "XS",
    IF(Sales[Amount] < 500, "S",
        IF(Sales[Amount] < 2000, "M",
            IF(Sales[Amount] < 10000, "L", "XL"))))

-- DO
Band =
SWITCH(TRUE(),
    Sales[Amount] < 100,   "XS",
    Sales[Amount] < 500,   "S",
    Sales[Amount] < 2000,  "M",
    Sales[Amount] < 10000, "L",
    "XL"
)

Bonus: Wer eine neue Bedingung einfügen muss, macht das in einer Zeile — nicht in einer Klammer-Orgie.

05DISTINCTCOUNT kostet

DISTINCTCOUNT ist eine der teuersten DAX-Funktionen überhaupt, weil sie einen Hash über alle eindeutigen Werte bauen muss. Wenn du garantieren kannst, dass eine Spalte bereits eindeutig ist — etwa ein Primärschlüssel der Dimensionstabelle — ist COUNTROWS oder COUNT bis zu einer Größenordnung schneller.

-- AVOID
Active Customers = DISTINCTCOUNT(Sales[CustomerKey])

-- DO (wenn du über die Dimension zählst und Filterkontext greift)
Active Customers = COUNTROWS(Customer)

In großen Modellen mit hoher Kardinalität ist diese Regel oft der Unterschied zwischen 3 Sekunden und 30 Sekunden Report-Ladezeit.

06ALL(T[Col]) statt ALL(Table)

ALL(Table) entfernt jeden Filter auf der gesamten Tabelle — inklusive solcher, die du eigentlich behalten wolltest. Das führt zu subtilen Bugs in Time-Intelligence-Measures oder Prozent-vom-Gesamt-Berechnungen, weil plötzlich auch Slicer auf anderen Spalten ignoriert werden.

-- AVOID: killt auch den Region- oder Year-Filter
Pct of Total = DIVIDE([Revenue], CALCULATE([Revenue], ALL(Sales)))

-- DO: entfernt nur den Produkt-Filter, alle anderen Slicer bleiben wirksam
Pct of Product Total = DIVIDE([Revenue], CALCULATE([Revenue], ALL(Product[ProductName])))

Faustregel: Schreibe immer so präzise wie möglich hin, welche Filter du entfernen willst. Alles andere ist Abrüstung mit dem Vorschlaghammer.

07DIVIDE() statt /-Operator

Der /-Operator wirft bei Division durch Null einen Fehler — was im Report als graue Zelle oder komplett abstürzendes Visual endet. DIVIDE() gibt standardmäßig BLANK() zurück und ist zusätzlich minimal schneller, weil der Fehlerbehandlungs-Overhead in der Engine intern optimiert ist.

-- AVOID
Margin % = (Sales[Revenue] - Sales[Cost]) / Sales[Revenue]

-- DO
Margin % = DIVIDE(Sales[Revenue] - Sales[Cost], Sales[Revenue])

-- DO (mit explizitem Alternativwert)
Margin % = DIVIDE(Sales[Revenue] - Sales[Cost], Sales[Revenue], 0)

Gerade in Dashboards mit dynamischen Slicern ist das Gold wert: ein leerer Filter darf dein Visual nicht in den Abgrund reißen.

08REMOVEFILTERS() statt ALL()

Seit DAX 2019 gibt es REMOVEFILTERS() — die semantisch eindeutige Variante von ALL(), wenn es als CALCULATE-Modifier eingesetzt wird. Funktional identisch, aber der Intent ist beim Code-Review sofort klar: „Hier entferne ich Filter, ich iteriere nicht über eine Tabelle."

-- Technisch identisch, aber REMOVEFILTERS ist selbsterklärend
Pct of Total =
DIVIDE(
    [Revenue],
    CALCULATE([Revenue], REMOVEFILTERS(Product[Category]))
)

Codebasen, die konsequent zwischen ALL (Tabellenfunktion für Iteratoren) und REMOVEFILTERS (CALCULATE-Modifier) trennen, sind messbar schneller zu warten. Ein stilistischer Unterschied — aber einer, der sich in jedem Handover bezahlt macht.

09ISBLANK() statt = BLANK()

BLANK() ist in DAX kein Wert im klassischen Sinn — es verhält sich je nach Kontext wie 0, wie leerer String oder wie „nichts". Ein IF(Sales[Amount] = BLANK(), …) produziert deshalb subtile Fehler, weil 0 = BLANK() in DAX TRUE ergibt. ISBLANK() prüft explizit auf die BLANK-Semantik und ist die einzig korrekte Variante.

-- AVOID: matcht auch auf 0 oder leeren String
IF([Revenue] = BLANK(), "keine Daten", FORMAT([Revenue], "#,0"))

-- DO
IF(ISBLANK([Revenue]), "keine Daten", FORMAT([Revenue], "#,0"))

Einmal gelernt, nie wieder vergessen — und die Regel, die bei jedem Junior-Code-Review als erstes auffällt.

Data Modeling — 9 Regeln

Architektur-Blueprint auf Bildschirm mit vernetzten Nodes – Symbolbild für Star Schema und Data Modeling
Photo: Taylor Vick / Unsplash

Das Datenmodell ist das Fundament. Jeder Fehler hier multipliziert sich durch jede Measure und jedes Visual, das darauf aufbaut. Keine Abkürzungen — die folgenden neun Regeln sind nicht verhandelbar.

01Star Schema — immer

Kein Snowflake, keine „aber-in-unserem-Fall", keine Diskussion. Die VertiPaq-Engine ist für Star Schemas optimiert: eine Fact-Table in der Mitte, Dimensionstabellen drumherum, 1:n-Beziehungen von Dim zu Fact. Jede Normalisierung darüber hinaus kostet Performance, verkompliziert DAX und erschwert Wartung.

Wenn du Snowflake-artige Strukturen in deiner Quelle hast (Kategorie → Unterkategorie → Produkt), denormalisiere sie in Power Query zu einer einzigen Produkt-Dimension. Die paar MB mehr an Speicher sind im Vergleich zur Performance und Lesbarkeit völlig vernachlässigbar.

Faustregel: Wenn du zwei Dimensionstabellen per Beziehung verbindest, machst du es falsch.

02Eigene Date-Tabelle

Die „Auto Date/Time"-Funktion legt für jede Datumsspalte eine versteckte Date-Tabelle an — inklusive aller Hierarchien. In einem Modell mit 15 Datumsspalten sind das 15 zusätzliche Tabellen, die du weder siehst noch verwalten kannst. Sie blähen das Modell auf, erschweren Time Intelligence und führen zu inkonsistenten Fiscal-Year-Logiken.

Stattdessen: eine dedizierte Date-Tabelle, als Date-Table markiert (Mark as Date Table), mit kontinuierlichen Datumswerten vom Anfang bis zum Ende deines Analysezeitraums und allen benötigten Kalenderhierarchien.

// Minimal-Template für eine Date-Tabelle in Power Query
let
    StartDate = #date(2020, 1, 1),
    EndDate   = Date.From(DateTime.LocalNow()),
    DayCount  = Duration.Days(EndDate - StartDate) + 1,
    Dates     = List.Dates(StartDate, DayCount, #duration(1,0,0,0)),
    Table     = Table.FromList(Dates, Splitter.SplitByNothing(), {"Date"}),
    Typed     = Table.TransformColumnTypes(Table, {{"Date", type date}}),
    Enriched  = Table.AddColumn(Typed, "Year", each Date.Year([Date]), Int64.Type)
in
    Enriched

Auto Date/Time in den Optionen ausschalten — projektweit, einmal, nie wieder.

03Bidi-Filter vermeiden

Bidirektionale Beziehungen sehen verlockend aus, wenn eine Measure nicht das gewünschte Ergebnis liefert. Sie sind aber einer der häufigsten Performance-Killer und eine der häufigsten Quellen für mehrdeutige Abfragepfade. In komplexen Modellen mit mehreren Fact-Tables produzieren sie Endlosschleifen oder falsche Aggregationen, die sich nicht reproduzieren lassen.

Der saubere Weg: unidirektionale Beziehungen als Standard, und bei konkretem Bedarf CROSSFILTER() auf Measure-Ebene einsetzen — lokal und kontrolliert.

Customers With Sales =
CALCULATE(
    DISTINCTCOUNT(Customer[CustomerKey]),
    CROSSFILTER(Sales[CustomerKey], Customer[CustomerKey], BOTH)
)

So bleibt der Bidi-Effekt auf diese eine Measure beschränkt und kontaminiert nicht das ganze Modell.

04Measures dediziert ablegen

Measures in Fact-Tables zu werfen ist bequem — aber sobald das Modell wächst, wird die Suche nach „wo war nochmal die Umsatz-Measure" zur Archäologie. Eine dedizierte Measure-Tabelle (leere Tabelle, keine physischen Spalten, nur Measures als Inhalt) gibt dir einen zentralen, durchsuchbaren Anlaufpunkt.

So baust du eine Measure-Tabelle: In Power Query eine leere Tabelle anlegen (= #table({"Dummy"}, {}) oder via Enter Data), die einzige Spalte im Modell verstecken, alle Measures per Home-Table-Property dorthin verschieben. Das Icon wechselt automatisch auf das Measure-Tabellen-Symbol.

In größeren Modellen empfiehlt sich zusätzlich eine Gruppierung via Display Folders: Finance\Revenue, Finance\Costs, Sales\Pipeline — skaliert deutlich besser als eine lange flache Liste.

05Integer-Keys statt Text

VertiPaq speichert jede Spalte in einem Dictionary. Integer-Spalten sind drastisch kleiner und schneller zu joinen als Textspalten — in der Praxis 3–5× schneller bei Beziehungs-Lookups und mit deutlich geringerem RAM-Footprint. Bei Schlüsseln, die im Report nie sichtbar sind, ist Text reine Verschwendung.

Umsetzung: Wenn deine Quelle nur Textschlüssel liefert (ProductCode = "SKU-AX-2291"), erzeuge in Power Query einen synthetischen Integer-Key via Table.AddIndexColumn oder einem deterministischen Hash. Der Text-Key bleibt als Attribut in der Dimension, die Beziehung läuft über Integer.

Gleiches gilt für zusammengesetzte Schlüssel: niemals als konkatenierten String über die Beziehung joinen — immer einen separaten Surrogate Key bauen.

06M:N vermeiden

Many-to-many-Beziehungen sind seit Power BI 2018 zwar nativ unterstützt — sollten aber trotzdem vermieden werden. Sie sind intern auf bidirektionale Bridge-Tables abgebildet, die komplexe Abfragepläne erzeugen und nicht-triviale Filter-Kontextprobleme auslösen.

Der robuste Weg: explizite Bridge-Table mit zwei 1:n-Beziehungen von der Bridge zu den beiden Dimensionen. Kostet eine zusätzliche Tabelle, macht das Verhalten aber deterministisch, DAX-freundlich und auditable.

Beispiel Customer ↔ SalesRep: nicht direkt M:N modellieren, sondern eine Bridge-Table CustomerSalesRep[CustomerKey, SalesRepKey] einziehen.

07Spalten entfernen — nicht nur ausblenden

Versteckte Spalten sind nicht weg. Sie belegen weiterhin Speicher, werden komprimiert, geladen, sortiert — einfach nur nicht angezeigt. In Modellen mit 50+ Spalten pro Tabelle, von denen 80 % nicht benötigt werden, ist das der größte einzelne Hebel für RAM-Einsparung.

Konsequenz: Im Power Query mit Table.SelectColumns oder Remove Other Columns gezielt herausnehmen, was wirklich im Modell gebraucht wird. Das macht nicht nur das Modell schlanker, sondern verkürzt auch die Refresh-Zeit.

Table.SelectColumns(Source, {"CustomerKey", "CustomerName", "Region", "SegmentKey"})

08Datentypen bewusst wählen

Die VertiPaq-Kompression ist auf niedrige Kardinalität und kleine Datentypen optimiert. Ein Fixed Decimal Number (4 Byte intern) oder ein Int32 spart bei großen Fact-Tables schnell Hunderte MB. Gleiches gilt für Datum vs. Datum/Uhrzeit: wenn die Uhrzeit keine Rolle spielt, ist ein reiner Date-Typ drastisch besser komprimierbar als ein DateTime.

Praxis-Tipp: Ab mehreren Millionen Zeilen lohnt der Griff zum DAX Studio VertiPaq Analyzer. Damit identifizierst du in zehn Minuten die 2–3 „fetten" Spalten, deren Typ-Optimierung das halbe Modell shrinkt.

09Inaktive Beziehungen für multiple Date Roles

Orders haben meistens mehrere relevante Daten: OrderDate, ShipDate, DeliveryDate. Drei aktive Beziehungen zur Date-Table sind nicht erlaubt — nur eine darf aktiv sein. Die anderen werden inaktiv definiert und per USERELATIONSHIP() in der Measure aktiviert.

Revenue by Ship Date =
CALCULATE(
    [Revenue],
    USERELATIONSHIP('Date'[Date], Sales[ShipDate])
)

Damit bleibt das Modell sauber, deterministisch — und du hast die volle Zeitdimensions-Funktionalität pro Datumsrolle. Der Fehler wäre, drei separate Date-Tabellen anzulegen; das ist nur dann legitim, wenn der Nutzer wirklich drei Datumsachsen nebeneinander filtern muss.

Power Query — 8 Regeln

Leiterplatte in Nahaufnahme – Symbolbild für Datenpipelines und Query Folding
Photo: Alexandre Debiève / Unsplash

Power Query ist die meistunterschätzte Schicht in Power BI. Hier fällt die Entscheidung, ob ein Refresh 30 Sekunden oder 30 Minuten dauert — und ob dein Modell morgens um 6 Uhr durchläuft oder die Ops-Kollegen anruft.

01Query Folding maximieren

Query Folding bedeutet, dass Power Query die Transformationen in die native Sprache der Quelle (SQL, CDM) übersetzt und dort ausführt — statt alle Rohdaten zu laden und in-memory zu verarbeiten. Bei Datenbank-Quellen ist das der Unterschied zwischen „Server macht's in 2 Sekunden" und „Gateway lädt 5 GB und macht's in 4 Minuten".

Jeder Schritt in deiner Query sollte folden. Ab dem ersten Schritt, der nicht foldet (erkennbar per Rechtsklick → View Native Query ausgegraut), ist der Rest der Pipeline ebenfalls in-memory. Deshalb: teure Operationen (Filter, Merges, Gruppierungen) früh, Folding-kritische Schritte ans Ende — oder in ein View bzw. eine Stored Procedure auslagern.

02Spalten früh entfernen

Je weniger Spalten du transportierst, desto schneller ist jeder nachfolgende Schritt. Remove Other Columns (mit expliziter Whitelist) ist robuster als Remove Columns (Blacklist), weil neue Spalten in der Quelle nicht automatisch ins Modell rutschen.

// AVOID: bricht, wenn "SecretColumn" nicht mehr existiert
Table.RemoveColumns(Source, {"SecretColumn", "LegacyFlag"})

// DO: stabil gegen Schema-Änderungen, explizit dokumentiert
Table.SelectColumns(Source, {"OrderKey", "CustomerKey", "Amount", "Date"})

Faustregel: Spalten filtern vor Merges, Filtern, Groupings — in dieser Reihenfolge.

03Datentypen explizit setzen — kein Auto-Detect

Die automatische Typ-Erkennung rät basierend auf den ersten 1.000 Zeilen. Das geht lange gut — bis eine Zeile kommt, in der der String „—" statt einer Zahl steht und der Refresh bricht. Oder bis ein deutsches Datumsformat falsch interpretiert wird und alle Daten um drei Monate verschoben sind.

Table.TransformColumnTypes(Source, {
    {"OrderDate",    type date},
    {"Amount",       Currency.Type},
    {"Quantity",     Int64.Type},
    {"CustomerName", type text}
})

Und: „Promoted Headers" plus „Changed Type" am Query-Anfang — auto-generiert beim Excel/CSV-Import — gehören kritisch reviewt und meist an eine spätere Position verschoben.

04Filtern vor Mergen

Ein Merge materialisiert potenziell beide Inputs komplett. Wenn du 10 Millionen Zeilen mit einer Lookup-Table joinst, obwohl du nachher nur 50.000 Zeilen brauchst, ist das reine Ressourcenverschwendung — im Gateway, auf dem Refresh-Server, und in deiner Wartezeit.

// AVOID
Merged   = Table.NestedJoin(Sales, {"CustomerKey"}, Customer, {"CustomerKey"}, "Cust"),
Filtered = Table.SelectRows(Merged, each [Region] = "DACH")

// DO
FilteredSales = Table.SelectRows(Sales, each [Region] = "DACH"),
Merged        = Table.NestedJoin(FilteredSales, {"CustomerKey"}, Customer, {"CustomerKey"}, "Cust")

Als Bonus foldet die zweite Variante deutlich häufiger sauber in die Quelle.

05Table.Buffer() bei mehrfach referenzierten Tabellen

Power Query ist lazy und re-evaluiert Queries, wenn sie mehrfach referenziert werden. Wenn du also eine teure Quell-Abfrage in drei verschiedenen Downstream-Queries nutzt, läuft sie standardmäßig dreimal. Table.Buffer() erzwingt, dass die Tabelle einmal in den Speicher gezogen und dann aus dem Speicher bedient wird.

let
    Raw      = Sql.Database("server", "db"){[Name="ExpensiveView"]}[Data],
    Buffered = Table.Buffer(Raw)
in
    Buffered
Wichtig: Buffering killt Query Folding. Deshalb nur dort einsetzen, wo das Folding ohnehin an der Stelle endet — oder wo die mehrfache Ausführung nachweisbar teurer ist als der Folding-Verlust.

06try … otherwise für Fehlerbehandlung

Ein einzelner Fehler-Wert in einer Spalte kann in Power Query den gesamten Refresh stoppen. Mit try … otherwise fängst du lokal ab und lieferst einen kontrollierten Default.

Table.AddColumn(Source, "Ratio",
    each try [Numerator] / [Denominator] otherwise null,
    type number
)

Besonders wichtig bei Custom Columns, die aus Textfeldern parsen — Datumsstrings aus Fremdsystemen, Währungsformate mit Sonderzeichen, Boolean-Mapping aus „Y/N/1/0/yes".

07Parameter für Umgebungen

Jedes ernsthafte Projekt hat mindestens Dev, Staging und Prod. Server-Adressen, Datenbanknamen oder API-Keys hardcoded in Queries sind eine Zeitbombe: beim Deployment wird die falsche Quelle gezogen, der Bericht zeigt alte Daten, und niemand merkt es bis zum nächsten Management-Meeting.

// Parameter "ServerName" und "DatabaseName"
Sql.Database(ServerName, DatabaseName)

Ergänzt sich perfekt mit Dataflows oder Shared Datasets: Parameter einmal zentral, alle Berichte profitieren.

08Staging Queries (Enable Load = off)

Nicht jede Query muss im Modell landen. Zwischen-Queries, die nur zur Transformation dienen und deren Ergebnis nur intern referenziert wird (Lookup-Tabellen für spätere Merges, Parameter-Mappings), sollten auf Enable Load = off gestellt werden.

Vorteile: das Modell bleibt schlank, der Refresh ist schneller, und die Semantik im Dataset ist klarer. Konvention: Staging-Queries in einen eigenen Ordner und/oder mit Prefix kennzeichnen — bei 50+ Queries im Projekt unbezahlbar.

Visualisierung — 8 Regeln

Business-Dashboard mit Diagrammen und Kennzahlen auf einem Laptop – Symbolbild für Report-Design und Visualisierung
Photo: Luke Chesser / Unsplash

Ein perfektes Datenmodell mit einer schlechten Darstellung ist ein Bericht, den niemand nutzt. Hier gelten andere Regeln als im Backend: es geht um Wahrnehmung, kognitive Last und Entscheidbarkeit in Sekunden.

01Die 5-Sekunden-Regel

Öffne eine Reportseite. Zähle bis fünf. Wenn du bis dahin den Key Insight nicht erfassen kannst — die eine Zahl, die eine Richtung, den einen kritischen Ausreißer — ist die Seite überfrachtet. Nutzer scannen, sie lesen nicht. Jede Information, die nicht zum Kerninsight beiträgt, konkurriert mit ihm um Aufmerksamkeit.

Praktisch: vor jeder Seite eine klare Hypothese formulieren — „Der Leser muss in 5 Sekunden sehen, ob wir auf Plan sind." — und alles streichen, was nicht zu dieser einen Aussage beiträgt. Details wandern in Tooltips, Drill-Throughs oder Folgeseiten.

02Max 5–7 Visuals pro Seite

Mehr als sieben Visuals auf einer Seite sind kognitive Überforderung, kein Dashboard. Gleichzeitig bremsen viele Visuals das Rendering — jedes Visual ist eine eigene DAX-Query. In komplexen Modellen ist das der Unterschied zwischen 1 Sekunde und 8 Sekunden Seitenwechselzeit.

Wenn du mehr Informationen unterbringen musst: Tabs auf einer Seite, Bookmarks, Drill-Through oder eine zweite Seite im Report. „Alles auf eine Seite quetschen" ist der Charakteristik-Killer Nummer eins.

03Interactions steuern

Standardmäßig cross-filtert jedes Visual jedes andere auf derselben Seite. Das ist oft das Gegenteil von dem, was man will — ein Klick auf das Umsatz-KPI sollte vielleicht nicht das detaillierte Kunden-Ranking reset-filtern.

Im Format-Menü unter Edit Interactions kannst du pro Visual steuern, welche anderen Visuals auf Klicks reagieren: Filter, Highlight oder None. Auf gut designten Seiten ist das kein Detail, sondern ein Kernbestandteil der UX-Definition.

Ein Dashboard ohne explizit kuratierte Interactions ist kein Dashboard — es ist eine Sammlung unabsichtlich verbundener Kacheln.

04Kreisdiagramme — max 5 Segmente, oder gar nicht

Kreisdiagramme sind das wohl am häufigsten missbrauchte Visual überhaupt. Das menschliche Auge kann Winkel schlechter vergleichen als Längen — ein Balkendiagramm ist fast immer die bessere Wahl. Falls ein Pie Chart wirklich sinnvoll ist (Anteil an einem Ganzen, wenige klar unterscheidbare Segmente), dann mit maximal 5 Segmenten.

Alternativen: gestapeltes Balkendiagramm, 100%-gestapeltes Balkendiagramm, Treemap (für hierarchische Anteile) oder schlicht eine Tabelle mit Prozentwerten. In 90 % der Fälle klarer als ein Pie Chart.

05Drill-Through statt überfüllte Seiten

Drill-Through ist eines der unterschätztesten Power-BI-Features. Statt alle Dimensionen auf einer Seite zu zeigen, baust du eine Übersicht und eine oder mehrere Detail-Seiten, zu denen per Rechtsklick auf ein Visual gesprungen wird — gefiltert auf den Kontext des geklickten Elements.

Vorteile: die Übersichtsseite bleibt aufgeräumt, die Detail-Seite lädt nur bei Bedarf und nur für den relevanten Filter-Kontext, die Navigation wird für den Nutzer intuitiv. Fünf Minuten Setup, massiver UX-Gewinn.

06Farbe nur für Bedeutung, nie für Dekoration

Jede Farbe in einem Report sollte eine semantische Funktion haben: Warnung, Kategorie-Unterscheidung, Hervorhebung des Key Insights. „Weil es schöner aussieht" ist keine. Pre-attentive Wahrnehmung lenkt das Auge automatisch auf farbliche Ausreißer — wenn dort keine bedeutende Information sitzt, ist das verschwendete Aufmerksamkeit.

Praktisch: ein gedämpftes Farbschema als Baseline, eine Akzentfarbe für den Key Insight pro Seite, ein Warnsystem (Ampelfarben) für Abweichungen. Corporate-Design-Farben gehören in den Header und in Kategorieachsen — nicht in jede Balkenfläche.

07Tooltips für Kontext, nicht für Kerninfo

Tooltips sind großartig — für zusätzlichen Kontext. Trends, Vorjahresvergleiche, Erklärungen zu Datenquellen. Was sie nicht sein dürfen: der einzige Ort, an dem die Kerninformation sichtbar wird. Mobile-Nutzer, Bildschirm-Reader, Screenshots — alle sehen Tooltips nicht.

Power BI unterstützt zudem Report Page Tooltips — komplette Mini-Seiten als Tooltip. Sehr mächtig für Detail-Kontext, aber das Prinzip bleibt: Kerninfo im Visual, Anreicherung im Tooltip.

08Alt-Text für alle Visuals — Accessibility ist Pflicht

Barrierefreiheit ist in vielen Ländern rechtlich vorgeschrieben (BITV 2.0, EU-Richtlinie 2016/2102, ADA in den USA). Screen Reader benötigen Alt-Text für jedes Visual. In Power BI findest du das Feld unter Format Pane → General → Alt Text.

Pro Visual ein Satz, der beschreibt, was zu sehen ist und welcher Insight gezeigt wird: „Balkendiagramm: Umsatz je Region im aktuellen Quartal. Region DACH führt mit 4,2 Mio. € vor Benelux mit 2,8 Mio. €." Nicht nur barrierefrei, sondern zwingt dich auch, die Kernaussage jedes Visuals explizit zu formulieren — ein hervorragender Review-Check.

Was machst du mit diesen 34 Regeln?

Ein gutes Power-BI-Modell ist kein Zufall. Es ist das Ergebnis von Dutzenden kleiner, disziplinierter Entscheidungen, die jede für sich unscheinbar wirken — und in Summe den Unterschied zwischen „läuft halt" und „Enterprise-tauglich" ausmachen.

Die 34 Regeln in diesem Guide sind keine Theorie. Sie sind das, was in produktiven Projekten wirklich zählt — was den Unterschied macht zwischen einem Bericht, der das Management-Meeting überlebt, und einem, der nach drei Monaten durch den nächsten Prototyp ersetzt wird.

Der beste Weg, diesen Guide einzusetzen: öffne dein aktuelles Power-BI-Projekt. Geh die vier Domänen durch. Markiere für jede Regel, ob du sie umsetzt, teilweise umsetzt oder bewusst dagegen entschieden hast. Die Stellen, an denen du nur schulterzuckend weitergehst, sind deine nächsten drei technischen Schulden — und die ersten drei Punkte auf deinem Refactoring-Backlog.

Die Takeaways in einem Absatz

  • DAX: SUMMARIZECOLUMNS, VAR, DIVIDE, SWITCH — früh filtern, spät aggregieren.
  • Modeling: Star Schema, eigene Date-Tabelle, Integer-Keys, keine Bidi-Filter, keine M:N.
  • Power Query: Query Folding schützen, Spalten früh entfernen, Typen explizit setzen, vor dem Merge filtern.
  • Visualisierung: 5-Sekunden-Regel, max 5–7 Visuals, Farbe nur für Bedeutung, Alt-Text ist Pflicht.
  • Gemeinsamer Nenner: Handwerk vor Hype. Jede dieser Regeln spart im nächsten Sprint Stunden.

Das Cheat-Sheet als PDF

Pin das „Power BI Golden Rules"-Cheat-Sheet ans Board deines Teams. Kostenloser Download als druckfertiges PDF — DIN A3, markenkonform, ohne Anmeldung.

Cheat-Sheet herunterladen →

Dieser Guide ist das ausführliche Companion-Dokument zum „Power BI Golden Rules"-Cheat-Sheet. Du hast Feedback, eine Ergänzung oder einen eigenen Favoriten unter deinen Regeln? Schreib mir auf LinkedIn oder direkt an sw@weilerconsult.de — ich lese jede Nachricht. Weiler Consult GmbH · Business Intelligence & Power BI.