DAX Best Practices¶
Naming Conventions¶
- Follow SQLBI's DAX Naming Conventions for consistency
- Use semantic naming that describes what the measure/column does
- Fully qualify column references (
Table[Column]); do not qualify measures ([Measure]) - Denote ad-hoc columns created in
ADDCOLUMNS(),SUMMARIZE()etc with@(i.e[@NewCol]) for clarity
Code Quality & Maintainability¶
-
Prefer explicit measures over implicit measures 1
- Define measures explicitly rather than relying on automatic aggregation
- Makes intent clear and calculations reusable
-
Use variables for readability and performance 2
- Store intermediate calculations to avoid repeated evaluations
- Make complex formulas easier to understand and debug
-
Use DAX User Defined Functions to consolidate repeated code 3 4
- Create reusable functions for common calculation patterns
- Improves maintainability and consistency
-
Use
SWITCH()instead of nestedIF()statements- More readable and often better performance
- Easier to maintain when adding new conditions
Error Handling & Safety¶
-
Avoid converting BLANKs to values 5
- Can be expensive
-
Use
DIVIDE()for safe division 6 7- Automatically handles division by zero
- Returns BLANK instead of error
Performance Optimization¶
Iterator Functions¶
-
Avoid nesting iterator functions (i.e
SUMX(,SUMX(,)))- Nested iterations are O(n²) operations
- Consider collapsing to a single iteration when possible
-
Limit iterator functions over large tables
- Pre-aggregate data when possible
- Use variables to cache intermediate results
-
Filter on columns, not tables 8
- Use
FILTER(VALUES(Products[Colour]), Product[Colour]="Red") - Instead of
FILTER(Products, Product[Colour]="Red") - Reduces scan granularity and improves performance
- Use
Function Selection¶
-
Consider
SUMX(DISTINCT(),1)vsDISTINCTCOUNT()- Test both approaches for your specific scenario
- Performance can vary based on data distribution
-
Consider
IF.EAGER()when fusion between branches is possible 9- Can improve performance in certain scenarios
- Allows query engine to optimize both branches
-
Test with Performance Analyzer + DAX Studio
- Compare multiple variations of complex measures
- Use query plans to understand performance characteristics
Function-Specific Best Practices¶
Filtering & Context¶
-
Avoid
FILTER()as a filter argument 10- Use Boolean expressions as filter arguments whenever possible
- Import tables are optimized for column-based filtering
- Only use
FILTER()when necessary for complex comparisons involving:- Measures
- Multiple columns
- OR logic
- Use
KEEPFILTERS()to preserve existing filters
-
Use
TREATAS()instead ofINTERSECT()for virtual relationships- Better performance characteristics
-
Avoid
EARLIER()(use variables or row context transitions)- Variables are more readable and maintainable
- Less confusing than multiple row contexts
Aggregation & Counting¶
-
Use
COUNTROWS()instead ofCOUNT()11- It's more efficient, and so it will perform better
- It doesn't consider BLANKs contained in any column of the table
- The intention of formula is clearer, to the point of being self-describing
-
Use
SELECTEDVALUE()instead ofVALUES(), when determining if single value present in filter context 12- Returns scalar value instead of single-row table
- Automatically handles single/multiple selection scenarios
Table Functions¶
- Use
SUMMARIZE()only for grouping tuples 13- Don't add calculated columns in
SUMMARIZE() - Use
ADDCOLUMNS()orSUMMARIZECOLUMNS()for calculations - Avoids context transition issues
- Don't add calculated columns in
-
https://radacad.com/explicit-vs-implicit-dax-measures-in-power-bi/ ↩
-
https://learn.microsoft.com/en-us/dax/best-practices/dax-variables ↩
-
https://learn.microsoft.com/en-us/dax/best-practices/dax-user-defined-functions ↩
-
https://www.sqlbi.com/articles/introducing-user-defined-functions-in-dax/ ↩
-
https://learn.microsoft.com/en-us/dax/best-practices/dax-avoid-converting-blank ↩
-
https://learn.microsoft.com/en-us/dax/best-practices/dax-divide-function-operator ↩
-
https://www.sqlbi.com/articles/understanding-eager-vs-strict-evaluation-in-dax/ ↩
-
https://learn.microsoft.com/en-us/dax/best-practices/dax-avoid-avoid-filter-as-filter-argument ↩
-
https://learn.microsoft.com/en-us/dax/best-practices/dax-countrows ↩
-
https://learn.microsoft.com/en-us/dax/best-practices/dax-selectedvalue ↩
-
https://www.sqlbi.com/articles/best-practices-using-summarize-and-addcolumns/ ↩