There comes a moment when your Power BI report is beautiful, the model is clean, and yet one specific measure takes an eternity to calculate. Blaming the tool is easy, but almost always unfair: DAX is an extraordinarily fast language when written with awareness of how it works underneath. Optimizing measures is not black magic reserved for experts — it is knowing half a dozen principles and applying them with discipline. Let us go through them.
The two engines behind every measure
To optimize DAX, you first have to understand that every measure is resolved by two engines. The Storage Engine is fast, compressed, works on whole columns at once and can use several processor cores in parallel. The Formula Engine is slower, works row by row and uses a single core. The golden rule of performance is simple: do as much work as possible in the Storage Engine and as little as possible in the Formula Engine. Almost every technique that follows is a variation of this principle.

Technique 1: use variables to avoid repeating calculations
One of the easiest and most ignored improvements is storing intermediate results in variables with VAR. If a measure calculates the same expression three times, it is doing triple the work. By storing it in a variable and reusing it, the calculation happens only once. Beyond speed, variables make the measure readable and easier to debug — a rare case where what is faster is also what is cleaner.
Technique 2: filter columns, not whole tables
A very common mistake is using FILTER over a whole large table when a condition on a column would do. Writing CALCULATE( [Sales], FILTER( Table, Table[Year] = 2026 ) ) forces the engine to scan the whole table row by row; writing CALCULATE( [Sales], Table[Year] = 2026 ) lets the Storage Engine handle it far more efficiently. Whenever possible, apply the filter directly to the column and reserve the explicit FILTER only for conditions that truly require it.
Technique 3: beware iterators over huge tables
The X-family functions — SUMX, AVERAGEX and company — are powerful but scan the table row by row, Formula Engine territory. Over a small dimension, no problem. Over a fact table with millions of rows, a poorly thought-out iterator can be the cause of all the slowness. Often, you can reformulate the calculation so that the heavy work is a simple column aggregation, which the Storage Engine does in the blink of an eye.
Technique 4: reduce cardinality whenever possible
DAX speed depends directly on the number of distinct values the engines have to process. Very high cardinality columns — timestamps to the second, long unique identifiers — are performance's worst enemy. Storing the date separate from the time, or rounding what does not need extreme precision, reduces cardinality and speeds up everything that rests on those columns. It is an optimization in the model that reflects in every measure.
Technique 5: measure, do not guess
The most important rule of all: never optimize blindly. Power BI has the Performance Analyzer, which shows exactly how long each visual and each measure take. To go deeper, free tools like DAX Studio reveal how much time was spent in the Storage Engine and how much in the Formula Engine — the information that points directly at the problem. Optimizing without measuring is like operating without a diagnosis: you waste time fixing what was not broken.
A concrete case: from thirty seconds to under one
A team had a report where a "distinct customers with a purchase in the period" measure took about thirty seconds to open. The measure used a FILTER over the whole sales table, with millions of rows, inside an iterator. Running the Performance Analyzer, they saw that almost all the time was spent in the Formula Engine. They rewrote the measure to apply the filter directly to the column and replace the iterator with a native aggregation. The heavy work moved to the Storage Engine. The calculation time dropped from thirty seconds to under one. The model did not change, the data did not change — what changed was how the measure asked for the work.
The mental pattern that solves most cases
If there were a single idea to take away, it would be this: always ask "is this calculation being done column by column by the fast engine, or row by row by the slow engine?". When you notice a slow measure, look for iterators and filters over whole tables — they are the usual suspects. Reformulate so the Storage Engine does the bulk, and speed almost always appears. It is less about tricks and more about respecting how the tool thinks.
In practice
Next time a report drags, do not blame Power BI before looking at your measures with these eyes. Run the Performance Analyzer, find the slowest measure, and ask where it is doing too much work. Often, a two-line rewrite transforms the experience of everyone who uses the report. Which is the slowest measure in your main report — and have you measured where it loses time?