Why Anti-Patterns Matter
Every Power BI model accumulates technical debt over time. DAX measures written under deadline pressure often contain patterns that hurt performance, readability, and maintainability. We analyzed hundreds of models and identified the 10 most common anti-patterns.
1. Bare Division (No DIVIDE)
Using / instead of DIVIDE() is the single most common anti-pattern. When the denominator is zero, bare division returns Infinity — causing visual errors and confusing end users.
// ❌ Bad
Sales Margin = [Revenue] - [Cost]) / [Revenue]
// ✅ Good
Sales Margin = DIVIDE([Revenue] - [Cost], [Revenue])
Why it matters: DIVIDE() gracefully returns BLANK() on zero denominators, preventing "Infinity" from appearing in your reports.
2. Nested CALCULATE
Multiple CALCULATE() calls nested inside each other create confusing filter context transitions. Each CALCULATE resets the filter context, making behavior hard to predict.
// ❌ Bad
CALCULATE(
CALCULATE(SUM(Sales[Amount]), Sales[Region] = "US"),
DATESYTD('Date'[Date])
)
// ✅ Better — combine filters in a single CALCULATE
CALCULATE(
SUM(Sales[Amount]),
Sales[Region] = "US",
DATESYTD('Date'[Date])
)
3. SUMX Over Full Table
Using SUMX(table, expression) without filtering the table first iterates over every row — potentially millions of rows for a calculation that could be a simple SUM.
4. No VAR in Complex Measures
Repeating the same sub-expression multiple times in a measure is both a performance hit (evaluated multiple times) and a readability problem. VAR/RETURN is the fix.
// ❌ Bad — [Total Sales] evaluated twice
IF([Total Sales] > 1000, [Total Sales] * 0.1, 0)
// ✅ Good
VAR _sales = [Total Sales]
RETURN IF(_sales > 1000, _sales * 0.1, 0)
5. EARLIER Instead of VAR
EARLIER() is a legacy function from before VAR was introduced. It's harder to read and understand. Always use VAR instead.
6. Calculated Columns That Should Be Measures
Calculated columns are computed at refresh time and stored in memory. If the calculation doesn't need row context, it should be a measure — computed at query time with no storage cost.
7. Unused Measures
Dead code in your model adds confusion and makes maintenance harder. Regular audits should identify and remove measures that aren't referenced by any visual.
8. Missing Format Strings
Measures without explicit format strings rely on inherited formatting, which can produce inconsistent results across different visuals.
9. Long Measures Without Comments
Measures over 10 lines that lack comments are a maintenance nightmare. The original author might understand them, but nobody else will — including the original author 6 months later.
10. Star Schema Violations
Many-to-many relationships, bi-directional filters, and missing dimension tables all violate star schema best practices and cause unpredictable filter behavior.
Automate Your Audit
DaxAudit checks for all 10 of these anti-patterns (plus 21 more) automatically. Upload your model and get results in under 60 seconds.