|The Dangers of Non_Empty_Behavior|
|Written by Chris Webb|
|Monday, 18 March 2013 19:51|
Reposted from Chris Webb's blog with the author's permission.
One thing I see quite often when I'm reviewing MDX is the incorrect use of the Non_Empty_Behavior property. 99% of the time it's set without the developer really knowing what it does, and luckily in most cases it makes no difference to performance or what the calculation returns. However. in this post I'm going to argue that you should not use it unless you really know what you're doing and you can prove that it's beneficial - because if it's set incorrectly it can sometimes mean you get incorrect results from your queries.
First of all, what does Non_Empty_Behavior actually do? Basically, it's a hint to the SSAS Formula Engine that says that a calculation will return a null value if a given tuple also returns a null value. Moreover it's a hint that may or may not be ignored. For example, if you had an MDX calculated measure that was defined as
CREATE MEMBER CURRENTCUBE.[Measures].[MyMeasure] as [Measures].[Internet Sales Amount]*2;
It would be true to say that this calculated measure would always return a null value when the real measure [Measures].[Internet Sales Amount] returned null, so you would be able to say:
CREATE MEMBER CURRENTCUBE.[Measures].[MyMeasure] as [Measures].[Internet Sales Amount]*2
The late, great Mosha covered its use in detail in a number of blog posts from a few years ago:
These posts all refer to SSAS 2005, and from SSAS 2008 onwards a lot of work went on to ensure that most of the scenarios where Non_Empty_Behavior had been necessary to get good performance were optimised away. Certainly, in the simple example I showed above there would be no need to set Non_Empty_Behavior at all - the Formula Engine will already be able to optimise it as much as it can. This means that if you're on SSAS 2005 then Non_Empty_Behavior can be very useful for tuning calculations, but if you are using SSAS 2008 or greater it's highly likely that you do not need to use Non_Empty_Behavior at all. In fact, Mosha's advice back in 2009 when he did a preconference seminar at the PASS Summit on SSAS performance tuning was summed up in these two slides:
I think the message here is pretty clear.
So, it probably won't help your query performance, but why is it dangerous? Consider the following query:
This returns 1887 rows. However, if I set Non_Empty_Behavior incorrectly, like so:
The query now returns only 64 rows! By saying that the calculation will return a null value when Reseller Sales Amount is null - which is not the case - then rows that do in fact have values will get filtered out by the non empty clause. Clearly this is a bad thing, and also one that may be very hard to see happening when you are testing.
The example above was quite obviously wrong, and in fact it's quite hard on SSAS 2012 to find a query where Non_Empty_Behavior returns incorrect results. More often I see calculations like this:
.where Non_Empty_Behavior is set incorrectly (the calculation returns the Internet Sales Amount for the previous time period, and it's not true to say that the previous time period's sales will be null if the current time period's sales are null) but the query still returns the correct results. This is because, luckily, Non_Empty_Behavior is being ignored.
So, to sum up, if you are using SSAS 2008 or greater Non_Empty_Behavior may not solve your performance problem and may result in incorrect results. That is not to say that there are still one or two isolated scenarios where it can still be useful. Jorg Klein came across one fairly recently and blogged about it here:
But these scenarios are few and far between. Therefore don't use it if you're not sure what it does!
Latest Author Articles
- Optimising SSAS Many-To-Many Relationships By Adding Redundant Dimensions
- If I Could Have New Features In SSAS Multidimensional, What Would They Be?
- A Closer Look At Power Query/SSAS Integration
- Bidirectional Relationships And Many-To-Many In The Power BI Designer
- MDX Solve Order, SCOPE_ISOLATION and the Aggregate() function