Rules / Performance

Measures using time intelligence and model is using Direct Query

warning MEASURES_USING_TIME_INTELLIGENCE_AND_MODEL_IS_USING_DIRECT_QUERY · ported · model layer · scope: Measure, CalculationItem

What it checks

Measures and calculation items that call a time intelligence function, in a model where at least one table is in DirectQuery mode.

Each finding names the measure, as [Sales Last Year]. A calculation item is named on its own, as Prior Year, with its group beside it, as calculation group 'Time Intelligence'.

Example

Fires the rule
table Sales
	column 'Order Date'
		dataType: dateTime
		formatString: mm/dd/yyyy
		sourceColumn: OrderDate

	column Amount
		dataType: decimal
		summarizeBy: sum
		sourceColumn: Amount

	measure 'Sales Last Year' = CALCULATE(SUM('Sales'[Amount]), SAMEPERIODLASTYEAR('Date'[Date]))
		formatString: #,0

	partition Sales = m
		mode: directQuery
		source = let Source = Sql.Database("finance", "Warehouse"), Sales = Source{[Item = "Sales"]}[Data] in Sales

table Date
	dataCategory: Time

	column Date
		dataType: dateTime
		isKey
		formatString: mm/dd/yyyy
		sourceColumn: Date
After the fix
table Sales
	column 'Order Date'
		dataType: dateTime
		formatString: mm/dd/yyyy
		sourceColumn: OrderDate

	column Amount
		dataType: decimal
		summarizeBy: sum
		sourceColumn: Amount

	column 'Amount Prior Year'
		dataType: decimal
		summarizeBy: sum
		sourceColumn: AmountPriorYear

	measure 'Sales Last Year' = SUM('Sales'[Amount Prior Year])
		formatString: #,0

	partition Sales = m
		mode: directQuery
		source = let Source = Sql.Database("finance", "Warehouse"), Sales = Source{[Item = "vwSalesWithPriorYear"]}[Data] in Sales

table Date
	dataCategory: Time

	column Date
		dataType: dateTime
		isKey
		formatString: mm/dd/yyyy
		sourceColumn: Date

Why it matters

Time intelligence functions build sets of dates and evaluate the measure over each set. In Import mode that is in-memory work. In DirectQuery each set becomes a query, or a long list of dates inside one, sent to the source on every visual refresh, and sources are rarely fast at it. The functions work, but a page of year-to-date and prior-year cards can take many seconds to render.

How to fix it

Either take the model out of DirectQuery or take the time intelligence out of the measure. For the first, select the table in Power BI Desktop's model view and set Storage mode to Import in the Properties pane, which is the partition's mode: import line in the TMDL file; the finding clears only once no table in the model is left in DirectQuery, because the condition is about the model and not about the tables the measure happens to read. For the second, move the comparison into the data: add the prior period's value to each row in the source view or the warehouse, load it as an ordinary column, and write the measure as a SUM over it, which is what the example above does. Where neither is possible, keep the number of time intelligence measures on one page small and cache what you can in the source, because every one of them is another round trip.

When to ignore it

The common false alarm is a measure that has nothing to do with the DirectQuery table. The rule reads the model, not the query path, so one small DirectQuery table kept for real-time status will report every time intelligence measure in the model, including the ones that run entirely over imported tables. Check which tables the measure actually touches before you act on it. A source that answers quickly is the second case: a well-indexed warehouse over a few million rows returns a year-to-date query in well under a second, and a page that renders fast is not a problem whatever the rule says. Time the visual before rewriting anything. What is not a legitimate exception is a large DirectQuery fact table over a source you do not control, where the finding is naming the reason the report is slow.

To ignore this rule on one object, add annotation pbiplint.ignore = MEASURES_USING_TIME_INTELLIGENCE_AND_MODEL_IS_USING_DIRECT_QUERY under the object in its TMDL file. Power BI Desktop keeps the annotation. To turn the rule off for a whole project, set "MEASURES_USING_TIME_INTELLIGENCE_AND_MODEL_IS_USING_DIRECT_QUERY": "off" under rules in pbiplint.config.json.

Quirks

Ported from Microsoft's Best Practice Analyzer ruleset (opens in a new tab).

Check a model for this Improve this page (opens in a new tab)