What is Super DAX?
In a recent post, I mentioned something called Super DAX without giving it a very detailed explanation. If you’ve been working with SSAS for a few years and have a couple of Tabular projects under your belt, you may already be familiar with some of the performance improvements that roll up under the term “Super DAX” and introduced in SSAS 2016. But for the sake of completeness (and my own quest for knowledge) I’ve compiled a list of enhancements from several sources in hopes of building a better understanding of the term: Super DAX
This is the codename for a project that brings performance enhancements to DAX in two areas:
- More performant queries from client tools that use DAX
- Optimization of measure execution
“Super DAX” helps reduce the chattiness between DAX clients and Analysis Services. The vast majority of Power BI visuals (both for the service and desktop) have been rewritten to issue a single “Super DAX” query, which in turn requires only a single storage engine query (VertiPaq or DirectQuery), at least for simple measures. Previously, depending on chart type and fields you might get anywhere between 3 to hundreds of storage engine queries.
In addition to query optimizations, measure execution has been streamlined to boost performance of any client tool, such as Excel, Datazen, or SSRS. Let’s take a look at a few examples:
- Variables have been introduced to DAX: In a query or measure, evaluate an expression once and use the results many times, thus reducing the times the expression is executed.
- Strict evaluation of IF/SWITCH: A branch whose condition is false will no longer result in storage engine queries. Previously, branches were eagerly evaluated but results discarded later on.
- Non empty calculation optimizations: Just a single scan is needed for non empty results, instead of multiple scans in previous version of SSAS.
- Measure Fusion: Multiple measures from the same table are combined into a single storage engine query.
- Grouping sets: When a query asks for measures at multiple granularities (Total/Year/Month), a single query is sent at the lowest level and the rest of the granularities are derived from that level, thus reducing the times the expression is executed.
- Redundant join elimination: A single query to the storage engine returns both the dimension columns and the measure values.
- Multiple result sets for DAX: Multiple results row sets from a single DAX query, as leveraged by Power BI to share intermediate results across multiple result sets.
- Join orders: Improved ways to arrange join orders so that the joins start from the most restrictive intermediate table that correlates with most other intermediate tables.
- Countrows optimization: Use table heuristics to return results.
- Storage engine cache improvements: Storage engine now caches per database instead of per sever.
Additional DAX enhancements
- Non empty calculation – Reduces the number of scans needed for non empty.
- Measure Fusion – Multiple measures from the same table will be combined into a single storage engine – query.
- Grouping sets – When a query asks for measures at multiple granularities (Total/Year/Month), a single – query is sent at the lowest level and the rest of the granularities are derived from the lowest level.
- Redundant join elimination – A single query to the storage engine returns both the dimension columns and the measure values.
- Strict evaluation of IF/SWITCH – A branch whose condition is false will no longer result in storage engine queries. Previously, branches were eagerly evaluated but results discarded later on.
Favorite Super DAX Enhancement
From the references above, most of the Super DAX enhancements focus on reducing the number of storage engine queries. That feat, in and of itself, is an important one …anyone who’s had the pleasure of being tasked with performance tuning a pre-2016 tabular solution can confirm this to be true. The “chattiness” (i.e. lots of (sequential) storage engine requests) becomes painfully obvious when using DAX Studio to troubleshoot a poorly performing measure.
However, for me personally, the most important Super DAX improvement is/was “Strict evaluation of IF/SWITCH”.
IF ( < condition> , <true branch>, <false branch> )
Before Super DAX, the SSAS engine would evaluate both branches every time the measure was referenced. In many cases, it was no big deal as both branches were executing in just a few milliseconds. In other cases, however, when execution times of each branch were more costly and/or when the IF/SWITCH was being evaluated hundreds or even thousands of times (e.g. across an iterator) the performance could be TERRIBLE and you might end up spending hours/days trying to re-work the logic to avoid the IF/SWITCH statement.
Fortunately, Jason Thomas (b | t) came up with a very good work around, which I’ve successfully used many times when working w/ pre-2016 tabular solutions… so if you’re stuck working w/ pre-2016 tabular environments, and you care about performance, you should check it out!
What’s your favorite Super DAX feature?