tag:blogger.com,1999:blog-84861916321046543442024-03-18T21:06:50.217-07:00MDX and DAX topicsJeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.comBlogger15125tag:blogger.com,1999:blog-8486191632104654344.post-78278799014798389342015-09-27T13:03:00.001-07:002015-09-27T13:03:53.335-07:00Use Calculated Table to Figure out Monthly Subscriber Churn<br /><br />
With the recent GA of Power BI and the release of Excel 2016, Microsoft has unleashed to the public years of enhancements to its BI products. The rapid development enabled by the cloud service model means detailed documentation can be lagging behind product advancement. The freemium pricing strategy allows millions of business users easy access to Power BI products and services. I plan to resume blogging for at least the next 12 months to help spread the knowledge of the rich new capabilities of the data engine and the DAX programming language that serve as the foundation of all the exciting new features popping up rapidly in all Microsoft BI products. I have moved to a better blogging site <a href="http://pbidax.wordpress.com/">http://pbidax.wordpress.com</a> and here is my first post there <a href="https://pbidax.wordpress.com/2015/09/27/use-calculated-table-to-figure-out-monthly-subscriber-numbers/">Use Calculated Table to Figure out Monthly Subscriber Churn</a>.<br />
<br />Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com75tag:blogger.com,1999:blog-8486191632104654344.post-8773950248612808552013-06-15T11:32:00.000-07:002013-06-15T11:32:14.680-07:00The Currency Data Type and VertiPaq Caching
<span style="font-family: Calibri;">It’s been a while since I published my last blog post. That’s
not for lack of topics to write, but rather for lack of spare time. I switched
from a developer role to a development lead role a year and a half ago, while
life has always been busy at Microsoft, the extra responsibilities in the new
role had put too much on my plate. Moreover there have been a lot of changes
here at Microsoft to get the company transition into a “devices and services”
company, the flurry of initiatives and refocuses has kept many people extra busy
in the past year.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 8pt;">
<span style="font-family: Calibri;">I am writing today’s post since recently there was a long discussion
among some MVPs regarding a query performance concern in the Tabular database.
They have discovered that when a VertiPaq query performs certain arithmetic
operations on a column of <i style="mso-bidi-font-style: normal;">Currency</i>
data type, the calculation is not done directly inside the VertiPaq calculation
engine but rather done through a callback to the DAX calculation engine. For
example, if you issue the following MDX query against </span><a href="http://msftdbprodsamples.codeplex.com/releases/view/55330"><span style="color: #0563c1; font-family: Calibri;">AdventureWorks
Tabular Model SQL Server 2012</span></a><span style="font-family: Calibri;"> and capture the <b style="mso-bidi-font-weight: normal;">VertiPaq SE Query Begin/End</b> events inside SQL Server Profiler, you
would see CallbackDataID in the trace event to indicate a callback from the
VertiPaq calculation engine to the DAX calculation engine.<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="color: blue; font-family: Consolas; font-size: 9.5pt;">WITH</span><span style="font-family: Consolas; font-size: 9.5pt;"> <span style="color: blue;">MEASURE</span> <span style="color: #a31515;">'Internet Sales'</span>[m] = <o:p></o:p></span></div>
<span style="font-family: Consolas; font-size: 9.5pt;"><span style="mso-spacerun: yes;"> </span><span style="color: blue;">SUMX</span>(<span style="color: #a31515;">'Internet Sales'</span>,
[Unit Price] * [Unit Price Discount Pct])<o:p></o:p></span><br />
<span style="color: blue; font-family: Consolas; font-size: 9.5pt;">SELECT</span><span style="font-family: Consolas; font-size: 9.5pt;"> [m] <span style="color: blue;">ON</span> 0,<o:p></o:p></span><br />
<span style="font-family: Consolas; font-size: 9.5pt;">[Date].[Calendar Year].[Calendar Year].<span style="color: blue;">MEMBERS</span> <span style="color: blue;">ON</span> 1<o:p></o:p></span><br />
<span style="color: blue; font-family: Consolas; font-size: 9.5pt;">FROM</span><span style="font-family: Consolas; font-size: 9.5pt;"> [Model]<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;">
<span style="font-family: Consolas; font-size: 9.5pt;"><o:p> </o:p></span></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjP-lrI5lvvaeuAB-nES_C3MbmZ3cGlRc0HGFMH_GoDsRqqzqDLDrCNFadDjVv8WErW11bi66Yfoiohid7sKq6JYtiwBYVhfS21PCjNONAI-CUVVqXdkkD2nPDbUF4LGbbdNzMX1M5XMw0/s1600/CallbackDataID.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="80" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjP-lrI5lvvaeuAB-nES_C3MbmZ3cGlRc0HGFMH_GoDsRqqzqDLDrCNFadDjVv8WErW11bi66Yfoiohid7sKq6JYtiwBYVhfS21PCjNONAI-CUVVqXdkkD2nPDbUF4LGbbdNzMX1M5XMw0/s640/CallbackDataID.png" width="640" /></a></div>
<div class="MsoNormal" style="margin: 0in 0in 8pt;">
<span style="mso-no-proof: yes;"><!--[if gte vml 1]><v:shapetype
id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t"
path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f">
<v:stroke joinstyle="miter"/>
<v:formulas>
<v:f eqn="if lineDrawn pixelLineWidth 0"/>
<v:f eqn="sum @0 1 0"/>
<v:f eqn="sum 0 0 @1"/>
<v:f eqn="prod @2 1 2"/>
<v:f eqn="prod @3 21600 pixelWidth"/>
<v:f eqn="prod @3 21600 pixelHeight"/>
<v:f eqn="sum @0 0 1"/>
<v:f eqn="prod @6 1 2"/>
<v:f eqn="prod @7 21600 pixelWidth"/>
<v:f eqn="sum @8 21600 0"/>
<v:f eqn="prod @7 21600 pixelHeight"/>
<v:f eqn="sum @10 21600 0"/>
</v:formulas>
<v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/>
<o:lock v:ext="edit" aspectratio="t"/>
</v:shapetype><v:shape id="Picture_x0020_2" o:spid="_x0000_i1025" type="#_x0000_t75"
style='width:462pt;height:59.25pt;visibility:visible;mso-wrap-style:square'>
<v:imagedata src="file:///C:\Users\jewang\AppData\Local\Temp\msohtmlclip1\01\clip_image001.png"
o:title=""/>
</v:shape><![endif]--><!--[if !vml]--><!--[endif]--></span><o:p></o:p><br /></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 8pt;">
<span style="font-family: Calibri;">Some MVPs went on to investigate which combinations of data
types and operations would fall into this category. To save people a lot of
research time and unnecessary guesswork, I’ll list the cases right here.<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 8pt;">
<span style="font-family: Calibri;">First let me give you some background information on why
MVPs are interested in this behavior. The VertiPaq calculation engine has a set
of built-in operations it can perform in a very efficient fashion. If an
operation is not natively supported, it calls back to the DAX calculation
engine to perform the operation on its behalf. A callback operation is not as
efficient as a native operation, but more importantly, a VertiPaq query
containing callback operations is not added to the VertiPaq cache. If you run
the above query again, you will not see the <b style="mso-bidi-font-weight: normal;">VertiPaq SE Query Cache Match</b> event for the VertiPaq query going to
the ‘Internet Sales’ table.<o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 8pt;">
<span style="font-family: Calibri;">The following table lists cases when VertiPaq calculation
engine calls back to DAX calculation engine to perform arithmetic operations.<o:p></o:p></span></div>
<br />
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: currentColor; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;">
<tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;">
<td style="background-color: transparent; border: 1pt solid windowtext; mso-border-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 112.25pt;" valign="top" width="150">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Arithmetic Operator<o:p></o:p></span></b></div>
</td>
<td style="background-color: transparent; border-color: windowtext windowtext windowtext rgb(0, 0, 0); border-style: solid solid solid none; border-width: 1pt 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.5pt;" valign="top" width="174">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Left Operand Data Type<o:p></o:p></span></b></div>
</td>
<td style="background-color: transparent; border-color: windowtext windowtext windowtext rgb(0, 0, 0); border-style: solid solid solid none; border-width: 1pt 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 139.5pt;" valign="top" width="186">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Right Operand Data Type<o:p></o:p></span></b></div>
</td>
</tr>
<tr style="mso-yfti-irow: 1;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 112.25pt;" valign="top" width="150">
<div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; text-align: center;">
<span style="font-family: Calibri;">+<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.5pt;" valign="top" width="174">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Currency<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 139.5pt;" valign="top" width="186">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Non-Currency<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 2;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 112.25pt;" valign="top" width="150">
<div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; text-align: center;">
<span style="font-family: Calibri;">+<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.5pt;" valign="top" width="174">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Non-Currency<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 139.5pt;" valign="top" width="186">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Currency<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 3;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 112.25pt;" valign="top" width="150">
<div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; text-align: center;">
<span style="font-family: Calibri;">-<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.5pt;" valign="top" width="174">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Currency<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 139.5pt;" valign="top" width="186">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Non-Currency<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 4;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 112.25pt;" valign="top" width="150">
<div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; text-align: center;">
<span style="font-family: Calibri;">-<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.5pt;" valign="top" width="174">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Non-Currency<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 139.5pt;" valign="top" width="186">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Currency<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 5;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 112.25pt;" valign="top" width="150">
<div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; text-align: center;">
<span style="font-family: Calibri;">*<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.5pt;" valign="top" width="174">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Currency<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 139.5pt;" valign="top" width="186">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Currency<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 6;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 112.25pt;" valign="top" width="150">
<div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; text-align: center;">
<span style="font-family: Calibri;">*<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.5pt;" valign="top" width="174">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Currency<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 139.5pt;" valign="top" width="186">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Real<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 7;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 112.25pt;" valign="top" width="150">
<div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; text-align: center;">
<span style="font-family: Calibri;">*<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.5pt;" valign="top" width="174">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Real<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 139.5pt;" valign="top" width="186">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Currency<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 8;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 112.25pt;" valign="top" width="150">
<div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; text-align: center;">
<span style="font-family: Calibri;">*<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.5pt;" valign="top" width="174">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Currency<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 139.5pt;" valign="top" width="186">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Date/Time<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 9;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 112.25pt;" valign="top" width="150">
<div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; text-align: center;">
<span style="font-family: Calibri;">*<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.5pt;" valign="top" width="174">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Date<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 139.5pt;" valign="top" width="186">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Real<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 10;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 112.25pt;" valign="top" width="150">
<div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; text-align: center;">
<span style="font-family: Calibri;">/<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.5pt;" valign="top" width="174">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Non-Currency<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 139.5pt;" valign="top" width="186">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Currency<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 11; mso-yfti-lastrow: yes;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 112.25pt;" valign="top" width="150">
<div align="center" class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; text-align: center;">
<span style="font-family: Calibri;">/<o:p></o:p></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.5pt;" valign="top" width="174">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Currency<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 139.5pt;" valign="top" width="186">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Real<o:p></o:p></span></i></div>
</td>
</tr>
</tbody></table>
<br />
<div class="MsoNormal" style="margin: 0in 0in 8pt;">
<span style="font-family: Calibri;">As you can see, all but one row in the table has at least
one operand of <i style="mso-bidi-font-style: normal;">Currency</i> data type and
you may wonder why <i style="mso-bidi-font-style: normal;">Currency</i> data type
is out of favor with the VertiPaq calculation engine. As it turns out, VertiPaq
engine stores <i style="mso-bidi-font-style: normal;">Currency</i> data as <i style="mso-bidi-font-style: normal;">Integer</i>s, e.g. $1234.5678 is stored as
12345678. Now you may wonder why <i style="mso-bidi-font-style: normal;">Integer</i>
* <i style="mso-bidi-font-style: normal;">Real</i> is not on the list but <i style="mso-bidi-font-style: normal;">Currency</i> * <i style="mso-bidi-font-style: normal;">Real</i> is. The answer lies in DAX rules governing the data types of
the results of arithmetic operations. In DAX, the result of <i style="mso-bidi-font-style: normal;">Integer</i> * <i style="mso-bidi-font-style: normal;">Real</i> is <i style="mso-bidi-font-style: normal;">Real</i>, but the
result of <i style="mso-bidi-font-style: normal;">Currency</i> * <i style="mso-bidi-font-style: normal;">Real</i> is <i style="mso-bidi-font-style: normal;">Currency</i>. So when VertiPaq calculates $12.3456 * 7.8, it does 123456
* 7.8 = 962956.8 and then it has to round the result to 962957 that represents
$96.2957. Currently, VertiPaq calculation engine only supports a subset of
conversions between basic data types and delegates the rest of the type
conversions to DAX calculation engine. The following table lists the basic DAX
data type conversions supported natively in VertiPaq calculation engine.<o:p></o:p></span></div>
<br />
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: currentColor; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;">
<tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;">
<td style="background-color: transparent; border: 1pt solid windowtext; mso-border-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.25pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">From<o:p></o:p></span></b></div>
</td>
<td style="background-color: transparent; border-color: windowtext windowtext windowtext rgb(0, 0, 0); border-style: solid solid solid none; border-width: 1pt 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">To<o:p></o:p></span></b></div>
</td>
</tr>
<tr style="mso-yfti-irow: 1;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.25pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Boolean<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Integer<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 2;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.25pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Boolean<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Real<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 3;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.25pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Integer<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Real<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 4;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.25pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Date/Time<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Real<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 5;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.25pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Boolean<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Date/Time<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 6;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.25pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Integer<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Date/Time<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 7;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.25pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Real<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Date/Time<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 8;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.25pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Integer<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Boolean<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 9;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.25pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Currency<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Boolean<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 10;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.25pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Date/Time<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Boolean<o:p></o:p></span></i></div>
</td>
</tr>
<tr style="mso-yfti-irow: 11; mso-yfti-lastrow: yes;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.25pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Real<o:p></o:p></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114">
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">Boolean<o:p></o:p></span></i></div>
</td>
</tr>
</tbody></table>
<br />
<div class="MsoNormal" style="margin: 0in 0in 8pt;">
<span style="font-family: Calibri;">Before we conclude today’s post, I want to add that this is
the behavior of SQL Server 2012 SP1. The Analysis Services team is busy adding
new capabilities to the product. Many of the limitations, such as VertiPaq
queries with callbacks missing VertiPaq cache, is likely to be lifted in a
future release.<o:p></o:p></span></div>
<o:p><span style="font-family: Calibri;"> </span></o:p><br />
Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com23tag:blogger.com,1999:blog-8486191632104654344.post-12333264886877256822012-03-04T15:16:00.000-08:002012-03-04T15:16:45.543-08:00DAX Query Plan, Part 3, Vertipaq Operators<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">The Vertipaq operators are an important subset of leaf-level
operators which are responsible for preparing and sending queries to the
Vertipaq Engine for execution and receiving query results. Table 1 is a list of
all Vertipaq operators. You can see them in <strong>DAX Query Plan</strong> trace events by running
the sample queries in column 3 against </span><a href="http://msftdbprodsamples.codeplex.com/releases/view/55330"><span style="color: blue; font-family: Calibri;">the tabular
AdventureWorks database</span></a><span style="font-family: Calibri;">.<o:p></o:p></span></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Table 1. Vertipaq
Operators<o:p></o:p></span></span></b></div>
<br />
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: currentColor; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;">
<tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;">
<td style="background-color: transparent; border: 1pt solid windowtext; mso-border-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Logical
Operators<o:p></o:p></span></span></b></div>
</td>
<td style="background-color: transparent; border-color: windowtext windowtext windowtext rgb(0, 0, 0); border-style: solid solid solid none; border-width: 1pt 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Description<o:p></o:p></span></span></b></div>
</td>
<td style="background-color: transparent; border-color: windowtext windowtext windowtext rgb(0, 0, 0); border-style: solid solid solid none; border-width: 1pt 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Example<o:p></o:p></span></span></b></div>
</td>
</tr>
<tr style="mso-yfti-irow: 1;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Scan_Vertipaq<o:p></o:p></span></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">This RelLogOp is the foundation of all other Vertipaq
logical operators. It represents a basic Vertipaq query that joins a root
table with related tables following many-to-one relationships, determines
which rows are retrieved by testing against Vertiscan predicates, and groups the
resultset by output columns.<o:p></o:p></span></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate ‘Product’<o:p></o:p></span></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 2;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">GroupBy_Vertipaq<o:p></o:p></span></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">This RelLogOp renames columns and adds rollup columns to a
Vertipaq query.<o:p></o:p></span></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate summarize(‘Product’, rollup(‘Product Category’[Product
Category Name], ‘Product’[Product Name]))<o:p></o:p></span></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 3;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Filter_Vertipaq<o:p></o:p></span></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">This RelLogOp adds a Verticalc predicate to a Vertipaq
query.<o:p></o:p></span></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate filter('Product', right([Product Name], 4) =
"Tire")<o:p></o:p></span></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 4;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Sum_Vertipaq<o:p></o:p></span></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">This ScaLogOp adds a SUM aggregation to a Vertipaq query.<o:p></o:p></span></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate row("x", sum('Internet Sales'[Sales
Amount]))<o:p></o:p></span></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 5;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Min_Vertipaq<o:p></o:p></span></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">This ScaLogOp adds a MIN aggregation to a Vertipaq query.<o:p></o:p></span></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate row("x", min('Internet Sales'[Sales
Amount]))<o:p></o:p></span></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 6;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Max_Vertipaq<o:p></o:p></span></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">This ScaLogOp adds a MAX aggregation to a Vertipaq query.<o:p></o:p></span></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate row("x", max('Internet Sales'[Sales
Amount]))<o:p></o:p></span></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 7;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Count_Vertipaq<o:p></o:p></span></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">This ScaLogOp adds a COUNT aggregation to a Vertipaq query.<o:p></o:p></span></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate row("x", countrows('Internet Sales'))<o:p></o:p></span></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 8;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">DistinctCount_Vertipaq<o:p></o:p></span></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">This ScaLogOp adds a DISTINCTCOUNT aggregation to a
Vertipaq query.<o:p></o:p></span></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate row("x", distinctcount('Internet Sales'[Due
Date]))<o:p></o:p></span></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 9;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Average_Vertipaq<o:p></o:p></span></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">This ScaLogOp adds an AVERAGE aggregation to a Vertipaq
query.<o:p></o:p></span></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate row("x", average('Internet Sales'[Sales
Amount]))<o:p></o:p></span></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 10;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Stdev.S_Vertipaq<o:p></o:p></span></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">This ScaLogOp adds a STDEV.S aggregation to a Vertipaq
query.<o:p></o:p></span></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate row("x", stdev.s('Internet Sales'[Sales
Amount]))<o:p></o:p></span></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 11;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Stdev.P_Vertipaq<o:p></o:p></span></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">This ScaLogOp adds a STDEV.P aggregation to a Vertipaq
query.<o:p></o:p></span></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate row("x", stdev.p('Internet Sales'[Sales
Amount]))<o:p></o:p></span></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 12;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Var.S_Vertipaq<o:p></o:p></span></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">This ScaLogOp adds a VAR.S aggregation to a Vertipaq query.<o:p></o:p></span></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate row("x", var.s('Internet Sales'[Sales
Amount]))<o:p></o:p></span></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 13;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Var.P_Vertipaq<o:p></o:p></span></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">This ScaLogOp adds a VAR.P aggregation to a Vertipaq query.<o:p></o:p></span></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate row("x", var.p('Internet Sales'[Sales
Amount]))<o:p></o:p></span></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 14;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Physical
Operators<o:p></o:p></span></span></b></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<br /></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<br /></div>
</td>
</tr>
<tr style="mso-yfti-irow: 15; mso-yfti-lastrow: yes;">
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext; border-style: none solid solid; border-width: 0px 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 130.1pt;" valign="top" width="173">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">VertipaqResult<o:p></o:p></span></span></i></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 400.5pt;" valign="top" width="534">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">This IterPhyOp iterates over the resultset returned by a Vertipaq
query.<o:p></o:p></span></span></div>
</td>
<td style="background-color: transparent; border-color: rgb(0, 0, 0) windowtext windowtext rgb(0, 0, 0); border-style: none solid solid none; border-width: 0px 1pt 1pt 0px; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 310.5pt;" valign="top" width="414">
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">You can find this operator in the physical plan tree after
running any of the above queries.<o:p></o:p></span></span></div>
</td>
</tr>
</tbody></table>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<br /></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">The Vertipaq Engine runs the fastest when it executes a query
in pure Vertiscan mode, which is when the query only contains simple
aggregations and simple predicates. A simple aggregation aggregates a single
column or counts rows of the table. A simple predicate, called Vertiscan
predicate in Table 1, typically looks like [Column] = 5 or [Column] IN { 5, 6,
7, … } or ([Column1], [Column2]) IN { (5, 6), (7, 8), … } where the numbers are
data IDs. Note that all column values are encoded as integer data IDs inside
the Vertipaq Engine. The Vertipaq Engine extends its basic Vertiscan capabilities
through its own calculation engine, called Verticalc. When aggregation
expressions or predicate expressions become more complex, the Vertipaq Engine builds
calculation trees to evaluate those expressions and can even call back to the DAX
Formula Engine for help on those operators it doesn’t support natively. For
example, when the aggregation expression is maxx('Internet Sales', year([Due
Date])), the Vertipaq Engine calls back to the DAX Formula Engine to evaluate
the <i style="mso-bidi-font-style: normal;">Year</i> function. Similarly, complex
predicate expressions are also evaluated using the Verticalc technology
therefore are called Verticalc predicates in Table 1. The Vertipaq Engine typically
runs slower when it has to invoke Verticalc evaluations during query execution
therefore the DAX Formula Engine converts filter predicates into Vertiscan slices
whenever possible.<o:p></o:p></span></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Ever since the MDX days, users have been complaining that the
Formula Engine is single-threaded when it executes a single query. The problem
is partially solved when the DAX Formula Engine pushes calculations down to the
Vertipaq Engine. Not only is the Vertipaq Engine multi-threaded, it is also
able to greatly reduce the number of calculations by taking advantage of large
blocks of continuous rows with identical values for those columns referenced by the calculation. Therefore, the DAX Formula Engine
tries very hard to push operations down to the Vertipaq Engine whenever
possible and it is highly desirable to see mostly Vertipaq operators in <strong>DAX
Query Plan</strong> events.<o:p></o:p></span></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Caveats of
Understanding Vertipaq Operators in DAX Query Plan Trees<o:p></o:p></span></span></b></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">As a brand new feature in Denali, the DAX Query Plan has
plenty of room for future improvements. Here I am going to highlight three
aspects of the current implementation which might confuse users who are trying
to read DAX Query Plans for the first time.<o:p></o:p></span></span></div>
<br />
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l1 level1 lfo2; text-indent: -0.25in;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-family: Calibri; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">1.</span><span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";"> </span></span></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">The display
of Vertipaq operators is too closely tied to the underlying implementation, as
a result, users might see multiple nested Vertipaq operators in a plan tree but
only a single Vertipaq query is issued. For example, if you run Query 1, you
will see four Vertipaq operators, <i style="mso-bidi-font-style: normal;">Sum_Vertipaq</i>,
<i style="mso-bidi-font-style: normal;">Filter_Vertipaq</i>, <i style="mso-bidi-font-style: normal;">Filter_Vertipaq</i>, <i style="mso-bidi-font-style: normal;">Scan_Vertipaq</i>,
in the <b style="mso-bidi-font-weight: normal;">DAX Query Plan/DAX Vertipaq
Logical Plan</b> event, as shown in Figure 1, but only a single <b style="mso-bidi-font-weight: normal;">Vertipaq SE Query Begin/Vertipaq Scan</b>
event. As you can see in Figure 1, a <i style="mso-bidi-font-style: normal;">Scan_Vertipaq</i>
operator serves as the foundation for all other Vertipaq operators, each aggregation
or Verticalc filter has its own operator, and the cascading operators are
displayed in a chain of parent-child relationships even though aggregations and
Verticalc filters are eventually folded into a single Vertipaq query.<o:p></o:p></span></span></div>
<br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;">
<span style="font-size: 12pt; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">// Query 1<o:p></o:p></span></span></div>
<span style="font-size: 12pt; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate
row("x",<o:p></o:p></span></span><br />
<span style="font-size: 12pt; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>sumx(<o:p></o:p></span></span><br />
<span style="font-size: 12pt; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 2;"> </span>filter(<o:p></o:p></span></span><br />
<span style="font-size: 12pt; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 3;"> </span>'Internet
Sales', <o:p></o:p></span></span><br />
<span style="font-size: 12pt; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 3;"> </span>Related(Product[List
Price]) < 10<o:p></o:p></span></span><br />
<span style="font-size: 12pt; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 3;"> </span>&&
Related(Customer[Yearly Income]) < 50000<o:p></o:p></span></span><br />
<span style="font-size: 12pt; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 2;"> </span>), <o:p></o:p></span></span><br />
<span style="font-size: 12pt; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 2;"> </span>[Sales Amount]<o:p></o:p></span></span><br />
<span style="font-size: 12pt; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>)<o:p></o:p></span></span><br />
<span style="font-size: 12pt; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">)<o:p></o:p></span></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><o:p><span style="font-family: Calibri;"></span></o:p></span></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhP7BmR82N-3pEHUK6Tgj7cSN-geSibuRg_UnvgZByL4bT1EAP_4fkv5kbfKx2_EebQpzLx7l6-XUUtd0TLs82osciwa4OTt4-af6pSKXIp12E0SdDTAn4XFUSFZbuSClFMyZvfRN5UJ0Q/s1600/Figure1_4Operators1Query.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="216" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhP7BmR82N-3pEHUK6Tgj7cSN-geSibuRg_UnvgZByL4bT1EAP_4fkv5kbfKx2_EebQpzLx7l6-XUUtd0TLs82osciwa4OTt4-af6pSKXIp12E0SdDTAn4XFUSFZbuSClFMyZvfRN5UJ0Q/s640/Figure1_4Operators1Query.png" width="640" /></a></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt; mso-no-proof: yes;"><v:shapetype coordsize="21600,21600" filled="f" id="_x0000_t75" o:preferrelative="t" o:spt="75" path="m@4@5l@4@11@9@11@9@5xe" stroked="f"><span style="font-family: Calibri;">
<v:stroke joinstyle="miter">
<v:formulas>
<v:f eqn="if lineDrawn pixelLineWidth 0">
<v:f eqn="sum @0 1 0">
<v:f eqn="sum 0 0 @1">
<v:f eqn="prod @2 1 2">
<v:f eqn="prod @3 21600 pixelWidth">
<v:f eqn="prod @3 21600 pixelHeight">
<v:f eqn="sum @0 0 1">
<v:f eqn="prod @6 1 2">
<v:f eqn="prod @7 21600 pixelWidth">
<v:f eqn="sum @8 21600 0">
<v:f eqn="prod @7 21600 pixelHeight">
<v:f eqn="sum @10 21600 0">
</v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:formulas>
<v:path gradientshapeok="t" o:connecttype="rect" o:extrusionok="f">
<o:lock aspectratio="t" v:ext="edit">
</o:lock></v:path></v:stroke></span></v:shapetype></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><o:p></o:p></span></div>
<br />
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l1 level1 lfo2; text-indent: -0.25in;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-family: Calibri; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">2.</span><span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";"> </span></span></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">As
mentioned in </span><a href="http://mdxdax.blogspot.com/2012/01/dax-query-plan-part-2-operator.html"><span style="color: blue; font-family: Calibri;">the
second installment</span></a><span style="font-family: Calibri;"> of the DAX Query Plan blog series, spools are not
first-class citizens in Denali DAX Query Plans, but users can still detect the
presence of spools in Denali DAX Query Plan trees indirectly through the
presence of physical operators which sit directly on top of spools such as the <i style="mso-bidi-font-style: normal;">Spool</i> LookupPhyOp or the <i style="mso-bidi-font-style: normal;">Spool_IterOnly</i>, <i style="mso-bidi-font-style: normal;">Spool_LookupOnly</i>, <i style="mso-bidi-font-style: normal;">Spool_SliceIndex</i>
IterPhyOps. Let’s call them spool operators in this post to make it easier to
refer to them. <span style="mso-spacerun: yes;"> </span>If you run Query 2 and
examine the physical plan tree shown in Figure 2, you can see a <i style="mso-bidi-font-style: normal;">Spool_IterOnly</i> operator with a child <i style="mso-bidi-font-style: normal;">VertipaqResult</i> operator. Since the real
child operator of <i style="mso-bidi-font-style: normal;">Spool_IterOnly</i> is a
spool, what’s with the <i style="mso-bidi-font-style: normal;">VertipaqResult</i>
IterPhyOp? As it turns out, some iterators supply the rows needed to fill a
spool when it is materialized and DAX Query Plan shows iterator subtrees which are
used to populate the spool as child operators of the spool operator. In Denali,
a spool is always constructed to receive the resultset of a Vertipaq query,
hence <i style="mso-bidi-font-style: normal;">VertipaqResult</i> operator is always
a child of a spool operator. An important property of a spool operator is <i style="mso-bidi-font-style: normal;">#Records</i>, highlighted in Figure 2, which
tells you how many rows of data are in the underlying spool and is currently
the most important property to help identify performance problems of a query. When
<i style="mso-bidi-font-style: normal;">VertipaqResult</i> is the sourcing
iterator, this property tells you how many records are returned by the Vertipaq
Engine.<o:p></o:p></span></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 0pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">// Query 2<o:p></o:p></span></span></div>
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate
values(Product[List Price])<o:p></o:p></span></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 0pt;">
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEvIubWT1Xp17fbvAcRKwXSgVYsBvVwRbh9BYSnltVkkA6w4T6jFgKRDM4DnzM81-3LBBKcG6c-RiIrH7atUxe6rtgWCQWKlsAUTeK3wZesYkqtpSblzDt_2Y388MOiGagT-zTItOdk_I/s1600/Figure2_HiddenSpoolOperator.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="48" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEvIubWT1Xp17fbvAcRKwXSgVYsBvVwRbh9BYSnltVkkA6w4T6jFgKRDM4DnzM81-3LBBKcG6c-RiIrH7atUxe6rtgWCQWKlsAUTeK3wZesYkqtpSblzDt_2Y388MOiGagT-zTItOdk_I/s640/Figure2_HiddenSpoolOperator.png" width="640" /></a></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt; mso-no-proof: yes;"></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 0pt;">
<br /></div>
<br />
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l1 level1 lfo2; text-indent: -0.25in;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-family: Calibri; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">3.</span><span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";"> </span></span></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">As stated
earlier, Verticalc evaluations may call back to the DAX Formula Engine for
unsupported logical operators which in turn would construct the corresponding
physical operator trees just as it would when the calculation happens entirely
in the Formula Engine. Sometimes the callback functions can be very expensive
themselves but those physical operators are not shown in the plan tree. If you
run Query 3 you will see in the <b style="mso-bidi-font-weight: normal;">Vertipaq
SE Query Begin</b> event, shown in Figure 3, that the Vertipaq Engine calls
back to the DAX Formula Engine for its help with the <i style="mso-bidi-font-style: normal;">Year</i> function, but the corresponding physical operator does not
show up in the <b style="mso-bidi-font-weight: normal;">DAX Query Plan/DAX
Vertipaq Physical Plan</b> event, shown in Figure 4.<o:p></o:p></span></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 0pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">// Query 3<o:p></o:p></span></span></div>
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate row("x", maxx('Internet Sales', year([Due
Date])))<o:p></o:p></span></span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJy-uKuGze1Xsgqwy21sQxkSUzYNZbqvdpxn43OUmY3eM9FFRwo6RmXrW4ANpVFdnZlFBPooy8tBuoE31XJGNTIZyiSLo6mG8TYiVuwi9v69-lirb0cCN5bK9K4GMocXBJTD6BxayVSj4/s1600/Figure3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="56" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJy-uKuGze1Xsgqwy21sQxkSUzYNZbqvdpxn43OUmY3eM9FFRwo6RmXrW4ANpVFdnZlFBPooy8tBuoE31XJGNTIZyiSLo6mG8TYiVuwi9v69-lirb0cCN5bK9K4GMocXBJTD6BxayVSj4/s640/Figure3.png" width="640" /></a></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt; mso-no-proof: yes;"></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><o:p></o:p></span></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjJJNTx2l1W1R2gl0VF7AuVJ0I9C94F1JyfnV73TN7gb2xJxsO0cgDKhLkQzovMF5YNmfVLv8QOYj_QPbGAw-30a9b84WBnlaNFq4eESz2iZSN7013ssvYPNDuXaFG5C9tllpGbZcWQfU/s1600/Figure4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="76" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjJJNTx2l1W1R2gl0VF7AuVJ0I9C94F1JyfnV73TN7gb2xJxsO0cgDKhLkQzovMF5YNmfVLv8QOYj_QPbGAw-30a9b84WBnlaNFq4eESz2iZSN7013ssvYPNDuXaFG5C9tllpGbZcWQfU/s640/Figure4.png" width="640" /></a></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt; mso-no-proof: yes;"></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><o:p></o:p></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Special
Properties of <i style="mso-bidi-font-style: normal;">Scan_Vertipaq</i> RelLogOp<o:p></o:p></span></span></b></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">As you have seen in the previous examples, the <i style="mso-bidi-font-style: normal;">Scan_Vertipaq</i>
operator is at the core of every Vertipaq query and has several special
properties worth mentioning here. To show you all the properties of <i style="mso-bidi-font-style: normal;">Scan_Vertipaq</i>, run Query 4 and then look
at its logical plan.<o:p></o:p></span></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 0pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">// Query 4<o:p></o:p></span></span></div>
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">define
measure 'Internet Sales'[Total Sales Amount] = Sum([Sales Amount])<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>calculatetable(<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 2;"> </span>addcolumns(<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 3;"> </span>crossjoin(values('Date'[Month]),
distinct('Product Category'[Product Category Name])),<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 3;"> </span>"YTD",<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 3;"> </span>calculate([Total
Sales Amount],<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 4;"> </span>filter(<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 5;"> </span>All('Date'[Month]),<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 5;"> </span>'Date'[Month]<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 5;"> </span><=<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 5;"> </span>earlier('Date'[Month])<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 4;"> </span>)<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 3;"> </span>)<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 2;"> </span>),<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 2;"> </span>'Date'[Calendar Year] =
2003<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>)<o:p></o:p></span></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 0pt;">
<br /></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 0pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Below is
the longest line I extracted from the logical plan with operator specific
properties in bold face. <o:p></o:p></span></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 0pt;">
<br /></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Scan_Vertipaq: RelLogOp
DependOnCols(1, 2)('Date'[Month], 'Product Category'[Product Category Name])
4-141 RequiredCols(1, 2, 133)('Date'[Month], 'Product Category'[Product
Category Name], 'Internet Sales'[Sales Amount]) <b style="mso-bidi-font-weight: normal;">Table='Internet Sales_78de3956-70d9-429f-9857-c407f7902f1e' -BlankRow
JoinCols(2)('Product Category'[Product Category Name]) SemijoinCols(3)('Date'[Month])<o:p></o:p></b></span></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">As you can see, in addition to the common properties <i style="mso-bidi-font-style: normal;">DependOnCols</i>, range of column numbers,
and <i style="mso-bidi-font-style: normal;">RequiredCols</i>, <i style="mso-bidi-font-style: normal;">Scan_Vertipaq</i> also has a couple of extra
properties:<o:p></o:p></span></span></div>
<br />
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Symbol; font-size: 12pt; line-height: 115%; mso-bidi-font-family: Symbol; mso-bidi-font-size: 11.0pt; mso-fareast-font-family: Symbol;"><span style="mso-list: Ignore;">·<span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Table<o:p></o:p></span></span></i></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Displays the internal ID of the
root table in Denali. I think this should change to user friendly table name in
the future.<o:p></o:p></span></span></div>
<br />
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Symbol; font-size: 12pt; line-height: 115%; mso-bidi-font-family: Symbol; mso-bidi-font-size: 11.0pt; mso-fareast-font-family: Symbol;"><span style="mso-list: Ignore;">·<span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Whether the blank row is requested<o:p></o:p></span></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">DAX introduced an </span><a href="http://sqlblog.com/blogs/marco_russo/archive/2011/03/08/difference-between-distinct-and-values-in-dax.aspx"><span style="color: blue; font-family: Calibri;">optional
blank row</span></a><span style="font-family: Calibri;"> to an IMBI table in order to deal with any incoming referential
integrity violations. When users want to include this blank row in the
resultset of a Vertipaq query, query plan shows +BlankRow; when users don’t
want to include the blank row in the resultset, query plan displays –BlankRow.
In Query 4 I deliberately used both the <i style="mso-bidi-font-style: normal;">Values</i>
function and the <i style="mso-bidi-font-style: normal;">Distinct</i> function
inside the <i style="mso-bidi-font-style: normal;">CrossJoin</i> function to
demonstrate the difference, see Figure 5 which was an excerpt from the logical
plan.<o:p></o:p></span></span></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiITNgYoqljAhGBlbvmGr64JVQvbAH8zvlApFxTAhkRC8q6xb2171LOBk-FZy32UEepzKppFuEBBfICT2V-OH2em6rHQrUQLvUuFLU4AfyVgbmSdqanlA7DkXu3jnAPHOxXyzjuIw8-C3c/s1600/Figure5_BlankRow.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="32" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiITNgYoqljAhGBlbvmGr64JVQvbAH8zvlApFxTAhkRC8q6xb2171LOBk-FZy32UEepzKppFuEBBfICT2V-OH2em6rHQrUQLvUuFLU4AfyVgbmSdqanlA7DkXu3jnAPHOxXyzjuIw8-C3c/s640/Figure5_BlankRow.png" width="640" /></a></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt; mso-no-proof: yes;"></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><o:p></o:p></span></div>
<br />
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Symbol; font-size: 12pt; line-height: 115%; mso-bidi-font-family: Symbol; mso-bidi-font-size: 11.0pt; mso-fareast-font-family: Symbol;"><span style="mso-list: Ignore;">·<span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">JoinCols<o:p></o:p></span></span></i></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">The columns from this table which
are needed for natural join with other tables. <i style="mso-bidi-font-style: normal;">JoinCols</i> are a subset of <i style="mso-bidi-font-style: normal;">DependOnCols</i>,
the latter is actually a union of the former and the <em>DependOnCols </em>of all semi-join filter operators.<o:p></o:p></span></span></div>
<br />
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Symbol; font-size: 12pt; line-height: 115%; mso-bidi-font-family: Symbol; mso-bidi-font-size: 11.0pt; mso-fareast-font-family: Symbol;"><span style="mso-list: Ignore;">·<span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><i style="mso-bidi-font-style: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">SemijoinCols<o:p></o:p></span></span></i></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">The columns from this table which
are needed for natural semi-join with filter tables. The DAX Formula Engine
simplifies the logical operator tree by converting most explicit semi-join filters
to Vertiscan slices or Verticalc slices so that the filtering operations happen
inside the Vertipaq Engine, and since <b style="mso-bidi-font-weight: normal;">DAX
Query Plan/DAX Vertipaq Logical Plan </b>events are fired after the
simplification stage, users typically don’t see the <i style="mso-bidi-font-style: normal;">SemijoinCols</i> property. But when <i style="mso-bidi-font-style: normal;">SemijoinCols</i>
do show up in the plan, the DAX Formula Engine may have to fetch more columns
back, join with the filter tables, and then remove unwanted <i style="mso-bidi-font-style: normal;">SemijoinCols</i> by grouping on the
desired output columns. When this happens, the Vertipaq operator can be quite expensive
as a lot of post-processing happens in the Formula Engine before the final
resultset can be returned.<o:p></o:p></span></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Understand
Performance Differences between Equivalent Queries<o:p></o:p></span></span></b></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">To conclude today’s post, let’s run two queries which are
written in different ways but return the same results and use DAX Query Plans
to figure out why they perform differently. Both Query 5 and Query 6 use the <i style="mso-bidi-font-style: normal;">AddColumns</i> function to simulate adding a
calculated column to the ‘Date’ table. The calculated column calculates the sum
of [Sales Amount] after filters the ‘Internet Sales’ table based on a predicate that depends on a column value from the current
row. While it is natural to write the calculation as sum of filter as done in
Query 5, to get much better performance, you should split the sum and the
filter into separate functions and then calculate the sum by adding the filter to
the filter context, see Query 6. Compare their logical plans, shown in Figure 6
and Figure 7 respectively, you can see that Query 5 executes both the <i style="mso-bidi-font-style: normal;">SumX</i> function and the <i style="mso-bidi-font-style: normal;">Filter</i> function in the Formula Engine
but Query 6 only executes the <i style="mso-bidi-font-style: normal;">Filter </i>function
in the Formula Engine but pushes the <i style="mso-bidi-font-style: normal;">SumX</i>
down to the Vertipaq Engine through the <i style="mso-bidi-font-style: normal;">Sum_Vertipaq</i>
operator. Since today we have learned that it is always good if calculations can
be pushed down to the Vertipaq Engine, Query 6 runs a lot faster than Query 5. So write your DAX expressions to take
advantage of Vertipaq operators.<o:p></o:p></span></span></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 0pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">// Query 5<o:p></o:p></span></span></div>
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate <o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>addcolumns(<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 2;"> </span>'Date', <o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 2;"> </span>"x",<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 2;"> </span>sumx(<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 3;"> </span>filter('Internet
Sales', [Order Date] <= [Date]), <o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 3;"> </span>[Sales
Amount]<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 2;"> </span>)<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>)<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><o:p><span style="font-family: Calibri;"> </span></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 0pt;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">// Query 6<o:p></o:p></span></span></div>
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">evaluate <o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>addcolumns(<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 2;"> </span>'Date', <o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 2;"> </span>"x", <o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 2;"> </span>calculate(<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 3;"> </span>sum('Internet
Sales'[Sales Amount]), <o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 3;"> </span>'Internet
Sales'[Order Date] <= earlier([Date]), <o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 3;"> </span>all('Date')<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 2;"> </span>)<o:p></o:p></span></span><br />
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>)<o:p></o:p></span></span><br />
<o:p><span style="font-family: Calibri;"> </span></o:p><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc9MiRzu_QX2B4vup4opQONLpXy_AI_TjZHICDRMw6mTYDv-vzY93rN8SGfDc0h0SUxdh-L284GDPny7uZAgbdZ0ODzXnqkrIRCxWu1YPgPGLhx34TqnF9clFsfqCla2EEYONxt-f9Y_o/s1600/Figure6_Q5LogOp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="136" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc9MiRzu_QX2B4vup4opQONLpXy_AI_TjZHICDRMw6mTYDv-vzY93rN8SGfDc0h0SUxdh-L284GDPny7uZAgbdZ0ODzXnqkrIRCxWu1YPgPGLhx34TqnF9clFsfqCla2EEYONxt-f9Y_o/s640/Figure6_Q5LogOp.png" width="640" /></a></div>
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="mso-no-proof: yes;"></span><o:p></o:p></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9wi3VMb5L0PhTOB94S0056liPXIDufx4R_O1dYfUA3I3S4jR7knW026ildfSdQrY39YCU8p5zLVTvvMn6El4-ACGuQQdy5hVBnytJ7F2Oqljw1VdBwVs2REGwJjJGPgUfNd8TZS5I1mY/s1600/Figure7_Q6LogOp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="154" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9wi3VMb5L0PhTOB94S0056liPXIDufx4R_O1dYfUA3I3S4jR7knW026ildfSdQrY39YCU8p5zLVTvvMn6El4-ACGuQQdy5hVBnytJ7F2Oqljw1VdBwVs2REGwJjJGPgUfNd8TZS5I1mY/s640/Figure7_Q6LogOp.png" width="640" /></a></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt;">
<span style="mso-no-proof: yes;"></span><o:p></o:p></div>Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com86tag:blogger.com,1999:blog-8486191632104654344.post-20555451846242141622012-01-31T23:38:00.000-08:002012-01-31T23:38:55.602-08:00DAX Query Plan, Part 2, Operator Properties<div class="WordSection1">
<a href="http://mdxdax.blogspot.com/2011/12/dax-query-plan-part-1-introduction.html"><span style="color: blue;">Last
time</span></a> we learned that DAX Query Plans are tree structures formatted as
indented text with each text line representing a single operator node in a tree.
A text line begins with an operator name followed by a colon and then properties
of the operator. Today we study the operator properties. You will see that for
the four types of operators, <span class="SpellE"><i style="mso-bidi-font-style: normal;">ScaLogOp</i></span>, <span class="SpellE"><i style="mso-bidi-font-style: normal;">RelLogOp</i></span>, <span class="SpellE"><i style="mso-bidi-font-style: normal;">LookupPhyOp</i></span>, and <span class="SpellE"><i style="mso-bidi-font-style: normal;">IterPhyOp</i></span>, each
type has a fixed set of common properties, and an individual operator may
contain extra properties to provide supplemental information. We’ll focus on the
semantics of the common properties in this post.</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">List of
Columns<o:p></o:p></span></b></div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="MsoNormal">
In a DAX Query Plan, a list of columns is shown as a list of
comma-delimited column numbers in a pair of parentheses plus a list of
comma-delimited fully-qualified column names in another pair of parentheses, see
Figure 1. In a degenerate case, two pairs of empty parentheses, (<span class="GramE">)(</span>), represent an empty list. Note that some properties, like
<span class="SpellE"><i style="mso-bidi-font-style: normal;">LookupCols</i></span>
and <span class="SpellE"><i style="mso-bidi-font-style: normal;">IterCols</i></span>, are not shown in the
plan when they contain no columns, but other properties, like <span class="SpellE"><i style="mso-bidi-font-style: normal;">DependOnCols</i></span> and
<span class="SpellE"><i style="mso-bidi-font-style: normal;">RequiredCols</i></span>, are always shown
even when their list of columns is empty.</div>
<div class="MsoNormal">
<br /></div>
<div class="WordSection1">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJqHu7NX-QV2cuZWpvwXbyVqlVsvZm7qfrhF7hmN3-JV702JlGj3gDG73j-XVyo7gScH5CqyC3ahZhGSRciMym6zuiP-ojwZnA8OK84m1lkjGHgHv4ApDlxbflX013oKhGb5BVyERJz5E/s1600/ListOfColumns.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="106" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJqHu7NX-QV2cuZWpvwXbyVqlVsvZm7qfrhF7hmN3-JV702JlGj3gDG73j-XVyo7gScH5CqyC3ahZhGSRciMym6zuiP-ojwZnA8OK84m1lkjGHgHv4ApDlxbflX013oKhGb5BVyERJz5E/s400/ListOfColumns.png" width="400" /></a></div>
<div class="MsoNormal">
<span style="mso-no-proof: yes;"><v:shapetype coordsize="21600,21600" filled="f" id="_x0000_t75" o:preferrelative="t" o:spt="75" path=" m@4@5 l@4@11@9@11@9@5 xe" stroked="f"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0 "></v:f><v:f eqn="sum @0 1 0 "></v:f><v:f eqn="sum 0 0 @1 "></v:f><v:f eqn="prod @2 1 2 "></v:f><v:f eqn="prod @3 21600 pixelWidth "></v:f><v:f eqn="prod @3 21600 pixelHeight "></v:f><v:f eqn="sum @0 0 1 "></v:f><v:f eqn="prod @6 1 2 "></v:f><v:f eqn="prod @7 21600 pixelWidth "></v:f><v:f eqn="sum @8 21600 0 "></v:f><v:f eqn="prod @7 21600 pixelHeight "></v:f><v:f eqn="sum @10 21600 0 "></v:f></v:formulas><v:path gradientshapeok="t" o:connecttype="rect" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype></span></div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="MsoNormal">
Column numbers are helpful when you need to disambiguate two
separate references to the same column. When you execute Query 1 against <a href="http://msftdbprodsamples.codeplex.com/releases/view/55330"><span style="color: blue;">the tabular
<span class="SpellE">AdventureWorks</span> database</span></a>, the logical plan, shown
in Figure 2, assigns different numbers to column <span class="GramE">‘Date’[</span>Month]: number 1 refers to the column in the outer
table scan and number 2 refers to the column in the inner table scan. Column
numbers are not chosen to be globally unique, but rather unique within a local
context.</div>
<pre class="code" style="margin-left: 15px;">// Query 1
define measure 'Internet Sales'[Total Sales Amount] = Sum([Sales Amount])
evaluate
calculatetable(
addcolumns(
values('Date'[Month]), -- outer scan
"YTD",
calculate([Total Sales Amount],
filter(
All('Date'[Month]), -- inner scan
'Date'[Month] -- refer to inner scan
<=
earlier('Date'[Month]) -- refer to outer scan
)
)
),
'Date'[Calendar Year] = 2003
)
</pre>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIMEr4a2GB2LgtqqosQFw4nh8A32gcvXn3c9Ebei8MwH_okbqfDY7eB2NxbX2IIQsq81WNERuE4RE10smLosNYnCX1Et7C3bXmjWJhj9gC6e44dkxDlQiyd1cA8Fw8UhOt5xQZdnZtJt4/s1600/ColumnNumbers.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="108" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIMEr4a2GB2LgtqqosQFw4nh8A32gcvXn3c9Ebei8MwH_okbqfDY7eB2NxbX2IIQsq81WNERuE4RE10smLosNYnCX1Et7C3bXmjWJhj9gC6e44dkxDlQiyd1cA8Fw8UhOt5xQZdnZtJt4/s400/ColumnNumbers.png" width="400" /></a></div>
<div class="MsoNormal">
<span style="mso-no-proof: yes;"></span></div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="MsoNormal">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">Common
Properties of Logical Plan Nodes</span></b></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Here are the properties common to all scalar logical
operators (<span class="SpellE"><i style="mso-bidi-font-style: normal;">ScaLogOp</i></span>):</div>
<div class="MsoNormal">
<br />
<br />
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Symbol; mso-bidi-font-family: Symbol; mso-fareast-font-family: Symbol;"><span style="mso-list: Ignore;">·<span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">DependOnCols</span></i></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-family: Calibri;">Marks columns from the left-side
of a tree on which the current logical operator depends. The current operator
may return a different value for each distinct combination of values of <i style="mso-bidi-font-style: normal;">DependOnCols</i>. Some table scanning
functions, e.g. <i style="mso-bidi-font-style: normal;">AddColumns</i> and <i style="mso-bidi-font-style: normal;">Filter</i>, create a row context using its
left child subtree and then evaluate the value of its right child subtree in
this context. This creates a dependency of the right child subtree on some
columns from the left child subtree. <i style="mso-bidi-font-style: normal;">DependOnCols</i>
captures this correlation between the two sides of a tree. Figure 3 shows an
example where a <i style="mso-bidi-font-style: normal;">ScaLogOp</i> subtree on
the right depends on some columns from two <i style="mso-bidi-font-style: normal;">RelLogOp</i>
subtrees on the left. At the bottom level of a tree, <i style="mso-bidi-font-style: normal;">DependOnCols</i> are established by either an explicit reference to a
column on the left or by a leaf table scan that joins directly or indirectly
(through SetFilter arguments of <i style="mso-bidi-font-style: normal;">Calculate</i>
function) to columns on the left. <i style="mso-bidi-font-style: normal;">DependOnCols</i>
are then propagated up through intermediate parent nodes to the root node of the
right subtree. Since DAX automatic cross-table filtering rules can be tricky
sometimes, beginners can use this property to help them figure out whether
their measures have the correct dependencies on external row contexts.<o:p></o:p></span></div>
<br />
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Symbol; mso-bidi-font-family: Symbol; mso-fareast-font-family: Symbol;"><span style="mso-list: Ignore;">·<span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><span style="font-family: Calibri;">Data type</span></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-family: Calibri;">One of the six data types DAX
supports. Values returned by the operator must be either of this data type or
be the BLANK value.<o:p></o:p></span></div>
<br />
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Symbol; mso-bidi-font-family: Symbol; mso-fareast-font-family: Symbol;"><span style="mso-list: Ignore;">·<span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">DominantValue</span></i></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-family: Calibri;">Captures the sparsity of a scalar
logical operator. When <i style="mso-bidi-font-style: normal;">DominantValue</i>
is NONE, the operator is dense, otherwise, it is sparse. When a scalar subtree
is sparse, DAX Formula Engine may pick a physical plan that can be orders of
magnitudes faster than a naïve physical plan. For example, if the predicate
child operator of a <i style="mso-bidi-font-style: normal;">Filter</i> operator
has a <i style="mso-bidi-font-style: normal;">DominantValue</i> of FALSE, DAX
Formula Engine can construct an iterator physical plan for the predicate
subtree that automatically skips large chunks of rows which would otherwise
return FALSE and be thrown away any way by the <i style="mso-bidi-font-style: normal;">Filter</i> operator.<span style="mso-spacerun: yes;"> </span>For users
coming from MDX background, this reminds them of the huge performance
difference between block mode vs. cell-by-cell mode. The technique to derive
the sparsity of a scalar subtree is very sophisticated and beyond the scope of
this post. It’s enough to know that a sparse scalar operator is the key to
great performance in many common query patterns.<o:p></o:p></span></div>
<br /></div>
<div class="MsoNormal">
<o:p> </o:p></div>
<div class="WordSection1">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBMYo-Nm3ReOHsO6tI32skp2kPNK1tR8YRZepYl2pyxa2R8rcdWUxReVM1oWB5frUG6iGhD3xMIjgVeBVEwtrbZAbP-QGW67I1JpfijU8JWljozTLbhiZXeTuU49NEgeZj6BUPqC18Avc/s1600/DependOnCols.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBMYo-Nm3ReOHsO6tI32skp2kPNK1tR8YRZepYl2pyxa2R8rcdWUxReVM1oWB5frUG6iGhD3xMIjgVeBVEwtrbZAbP-QGW67I1JpfijU8JWljozTLbhiZXeTuU49NEgeZj6BUPqC18Avc/s320/DependOnCols.png" width="292" /></a></div>
<div class="MsoNormal">
<span style="mso-no-proof: yes;"></span><o:p></o:p></div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="MsoNormal">
Here are properties common to all relational logical
operators (<span class="SpellE"><i style="mso-bidi-font-style: normal;">RelLogOp</i></span>):</div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="WordSection1">
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Symbol; mso-bidi-font-family: Symbol; mso-fareast-font-family: Symbol;"><span style="mso-list: Ignore;">·<span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">DependOnCols<o:p></o:p></span></i></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-family: Calibri;">Identical to the same named
property of <i style="mso-bidi-font-style: normal;">ScaLogOp</i>. The current
operator may return a different table for each distinct combination of values
of <i style="mso-bidi-font-style: normal;">DependOnCols</i>.<i style="mso-bidi-font-style: normal;"><o:p></o:p></i></span></div>
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Symbol; mso-bidi-font-family: Symbol; mso-fareast-font-family: Symbol;"><span style="mso-list: Ignore;">·<span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><span style="font-family: Calibri;">Range of column numbers<o:p></o:p></span></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-family: Calibri;">Although a relation may contain
many columns in its heading, DAX Formula Engine is smart enough to derive the
minimal subset of columns, see <i style="mso-bidi-font-style: normal;">RequiredCols</i>
property, which are needed to answer a query. To save space, DAX Query Plan
does not list all columns in the relation header, instead, it assigns
continuous column numbers to all columns in the relation header and only shows
<beginning column name>-<ending column name> as a part of the plan.
Note that this property may be missing when a relation has no column at all.<o:p></o:p></span></div>
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Symbol; mso-bidi-font-family: Symbol; mso-fareast-font-family: Symbol;"><span style="mso-list: Ignore;">·<span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">RequiredCols<o:p></o:p></span></i></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-family: Calibri;">This is the union of <i style="mso-bidi-font-style: normal;">DependOnCols</i> and the subset of columns
from the relation header which are needed to answer a query. For example, when
you examine the logical plan, shown in Figure 4, which corresponds to Query 2,
you can see that only one column, [Sales Amount], among 129 columns is a
required column. In case you are wondering why ‘Internet Sales’ table has 129
columns, you can find the answer in </span><a href="http://mdxdax.blogspot.com/2011/03/logic-behind-magic-of-dax-cross-table.html"><span style="color: blue; font-family: Calibri;">one
of my earlier posts</span></a><span style="font-family: Calibri;">.<o:p></o:p></span></div>
</div>
<div class="MsoNormal" style="margin-left: 0.25in;">
</div>
<pre class="code" style="margin-left: 15px;">// Query 2
define measure 'Internet Sales'[Total Sales Amount] = Sum([Sales Amount])
evaluate row("x", [Total Sales Amount])
</pre>
<div class="code" style="margin-left: 15px;">
<br /></div>
<div class="code" style="margin-left: 15px;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMipDc3QfiqQmc8n9jziclXGkdOfZ8v_iIesi534bRGKUFaEICQWd_l8-COmSkqvEUNhSE5GUQ2z3vnqYpi5s1xx5atPk2QDoCAxsVwr_3FGzTIsUoInli-ReKV8gmlcf6FFWGrq1b8zs/s1600/RequiredCols.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="56" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMipDc3QfiqQmc8n9jziclXGkdOfZ8v_iIesi534bRGKUFaEICQWd_l8-COmSkqvEUNhSE5GUQ2z3vnqYpi5s1xx5atPk2QDoCAxsVwr_3FGzTIsUoInli-ReKV8gmlcf6FFWGrq1b8zs/s400/RequiredCols.png" width="400" /></a></div>
<div class="MsoNormal">
<br /></div>
<div class="WordSection1">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">Common
Properties of Physical Plan Nodes<o:p></o:p></span></b></div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="MsoNormal">
In a physical plan tree, an iterator operator supplies rows
of column values to other nodes. When those rows are fed to a lookup operator, it can return a scalar value
from each input row. When the rows are fed to another iterator operator, it can output any number of rows of its own columns for each input row. Therefore, both iterators and
lookups share the same input property, <span class="SpellE"><i style="mso-bidi-font-style: normal;">LookupCols</i></span>, but they produce
different outputs. Let’s use the physical plan tree, shown in Figure 5, captured
from Query 1 to illustrate the common properties of physical operators.</div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="MsoNormal">
Here are the properties common to all lookup physical
operators (<span class="SpellE"><i style="mso-bidi-font-style: normal;">LookupPhyOp</i></span>):</div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="WordSection1">
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Symbol; mso-bidi-font-family: Symbol; mso-fareast-font-family: Symbol;"><span style="mso-list: Ignore;">·<span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">LookupCols<o:p></o:p></span></i></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-family: Calibri;">Columns supplied by an iterator
whose values are used to calculate a scalar value. In Figure 5, lookup
operators 1 and 2 read their input values from iterator 3; their output values
are later on used by their parent operator, <i style="mso-bidi-font-style: normal;">LessThanOrEqualTo</i>,
to calculate a Boolean value.<o:p></o:p></span></div>
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Symbol; mso-bidi-font-family: Symbol; mso-fareast-font-family: Symbol;"><span style="mso-list: Ignore;">·<span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><span style="font-family: Calibri;">Data type<o:p></o:p></span></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-family: Calibri;">One of the six data types DAX
supports. Values returned by the operator must be either of this data type or
be the BLANK value.<o:p></o:p></span></div>
</div>
<div class="WordSection1">
</div>
<div class="MsoNormal">
Here are the properties common to all iterator physical
operators (<span class="SpellE"><i style="mso-bidi-font-style: normal;">IterPhyOp</i></span>):</div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="WordSection1">
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Symbol; mso-bidi-font-family: Symbol; mso-fareast-font-family: Symbol;"><span style="mso-list: Ignore;">·<span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">LookupCols<o:p></o:p></span></i></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-family: Calibri;">Identical to the same named
property of <i style="mso-bidi-font-style: normal;">LookupPhyOp</i>. In Figure 5,
iterator 5, which doesn’t have the <i style="mso-bidi-font-style: normal;">LookupCols</i>
property, hence a pure iterator, supplies column 2 to iterator 4 as its <i style="mso-bidi-font-style: normal;">LookupCols</i> property which in turn
produces output column 1.<o:p></o:p></span></div>
<div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;">
<span style="font-family: Symbol; mso-bidi-font-family: Symbol; mso-fareast-font-family: Symbol;"><span style="mso-list: Ignore;">·<span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";">
</span></span></span><i style="mso-bidi-font-style: normal;"><span style="font-family: Calibri;">IterCols<o:p></o:p></span></i></div>
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.25in;">
<span style="font-family: Calibri;">Columns output by the iterator.<o:p></o:p></span></div>
</div>
<div class="WordSection1">
</div>
<div class="MsoNormal">
It is interesting to learn that a DAX iterator can be a pure
iterator, when it only has the <span class="SpellE"><i style="mso-bidi-font-style: normal;">IterCols</i></span> <span class="GramE">property,</span> or a table-valued function as in T-SQL Apply
operator when it has both <span class="SpellE"><i style="mso-bidi-font-style: normal;">LookupCols</i></span> and <span class="SpellE"><i style="mso-bidi-font-style: normal;">IterCols</i></span>
properties, or a pure row checker when it only has the <span class="SpellE"><i style="mso-bidi-font-style: normal;">LookupCols</i></span> property. In the last
case, the iterator serves the purpose of removing unwanted rows from other
iterators.</div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8VQ4_TxvPxyaM7s6Pso-ci3CadN_EzoVDhmSWKGB4PccaMYu73VV-ECY4sW63mWd3Iuiydh26BZ19H-bG8gK6YbBl-wwQBvkE5hMDaPBK1zFNvhACQHJ2f-z8yzl4yhwsrWCI2QeW-Gw/s1600/PhyOps.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="110" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8VQ4_TxvPxyaM7s6Pso-ci3CadN_EzoVDhmSWKGB4PccaMYu73VV-ECY4sW63mWd3Iuiydh26BZ19H-bG8gK6YbBl-wwQBvkE5hMDaPBK1zFNvhACQHJ2f-z8yzl4yhwsrWCI2QeW-Gw/s400/PhyOps.png" width="400" /></a></div>
<div class="MsoNormal">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt; mso-no-proof: yes;"></span></b><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><o:p></o:p></span></b></div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="MsoNormal">
For many DAX operators, common properties are all they offer.
But some DAX operators output additional properties to provide more information
about <span class="GramE">themselves</span>. I am not going to go into details
about all those operator-specific properties today because it would drag this
blog on far too long. I’ll only describe the proprietary properties of one
physical operator <span class="SpellE"><i style="mso-bidi-font-style: normal;">Spool_IterOnly</i></span> and postpone the
discussion of private properties of other operators in future blogs when we get
to study individual operators.</div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="MsoNormal">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">Special
Properties of Physical Operator <span class="SpellE"><i style="mso-bidi-font-style: normal;">Spool_IterOnly</i></span><i style="mso-bidi-font-style: normal;"><></i><o:p></o:p></span></b></div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="MsoNormal">
<span class="SpellE"><i style="mso-bidi-font-style: normal;">Spool_IterOnly</i></span><i style="mso-bidi-font-style: normal;"> </i>is a pure iterator that draws its rows from
an in-memory spool which is built through some other means. DAX Formula Engine
builds different flavors of in-memory spools, therefore <span class="SpellE"><i style="mso-bidi-font-style: normal;">Spool_IterOnly</i></span> along with several
other physical operators built from spools put the name of the spool in a pair
of angle brackets <> as a part of their names. This is partly caused by
the fact that spools are not first class citizens in query plan trees as of SQL
Server 2012. As a result, some spool specific properties are added directly to
physical operators built on top of the spool. Below is one line I extracted from
Figure 5 with <span class="SpellE"><i style="mso-bidi-font-style: normal;">Spool_IterOnly</i></span> specific
properties highlighted in bold face. They tell us that there are 12 records in
the spool and there are 240 key columns (most of which are compressed to 0 bit
hence record size is not as wide as it seems) and no value columns.</div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="WordSection1">
<span style="font-size: x-small;"><span class="SpellE">Spool_IterOnly</span><Spool>: <span class="SpellE">IterPhyOp</span> <span class="SpellE"><span class="GramE">IterCols</span></span><span class="GramE">(</span>1)('Date'[Month]) <b style="mso-bidi-font-weight: normal;">#Records=12 #<span class="SpellE">KeyCols</span>=240 #<span class="SpellE">ValueCols</span>=0<o:p></o:p></b></span></div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="MsoNormal">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">Summary<o:p></o:p></span></b></div>
<div class="WordSection1">
</div>
<div class="WordSection1">
</div>
<div class="MsoNormal">
Today we studied properties of operator nodes in DAX Query
Plan trees. We have learned that some properties are common to all operators of
one type and some properties are specific to a particular operator. While I
described in details those common properties, I just cited one example of
operator specific properties. Now that we have covered the basics of DAX Query
Plans, we will be able to explore ways to take advantage of them to investigate
performance issues in future posts. When we run into a specific operator of
importance, I’ll explain its associated properties at that time.</div>
<div class="WordSection1">
</div>
<div class="MsoNormal">
<o:p> </o:p></div>Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com7tag:blogger.com,1999:blog-8486191632104654344.post-23545034821682420452011-12-30T22:22:00.000-08:002011-12-31T09:40:46.117-08:00DAX Query Plan, Part 1, Introduction<div class="WordSection1">
<div class="MsoNormal">
<a href="http://www.microsoft.com/download/en/details.aspx?id=28145"><span style="color: blue;">SQL Server 2012 Analysis Services RC0</span></a> introduced a new SQL Server Profiler event class, <b style="mso-bidi-font-weight: normal;">DAX Query Plan</b>, under the <b style="mso-bidi-font-weight: normal;">Query Processing</b> event category. This
is an advanced and rich new event class, but there has been no official document
yet. Nonetheless, it has already attracted the attention of some users who are
pushing us to release more information as soon as possible. While waiting for an
official document to come out, I’ll try to find some spare time to temporarily
fill the gap by providing some background information on this event class in a
series of blog posts. As always, my goal is to provide accurate information with
sufficient technical details. There are plenty of other BI professionals who are
eager to help average users to learn this feature through intuitive, practical
examples. I’ll be using the tabular model <a href="http://msftdbprodsamples.codeplex.com/releases/view/55330"><span style="color: blue;"><span class="SpellE">AdventureWorks</span> for SQL Server 2012 RC0</span></a>
when I need to demonstrate different aspects of DAX query plans through
examples.</div>
<div class="MsoNormal">
<br />
The <b style="mso-bidi-font-weight: normal;">DAX Query
Plan</b> event class has four event subclasses:</div>
<div class="MsoNormal">
<ol>
<li>DAX <span class="SpellE">VertiPaq</span> Logical Plan</li>
<li>DAX <span class="SpellE">VertiPaq</span> Physical Plan</li>
<li>DAX <span class="SpellE">DirectQuery</span> <span class="SpellE">Algebrizer</span> Tree</li>
<li>DAX <span class="SpellE">DirectQuery</span> Logical Plan</li>
</ol>
</div>
<div class="MsoNormal">
</div>
<div class="MsoNormal">
Trace events of subclasses 1 and 2 are fired when a tabular
database is in <span class="SpellE">VertiPaq</span> mode. Trace events of
subclasses 3 and 4 are fired when a database is in <span class="SpellE">DirectQuery</span> mode. Since most tabular databases are likely to
run in <span class="SpellE">VertiPaq</span> mode, I’ll focus my discussions on the
first two types of events.</div>
<div class="MsoNormal">
<br />
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">Logical
Plans and Physical Plans<o:p></o:p></span></b></div>
<div class="MsoNormal">
<br />
DAX Formula Engine evaluates a DAX expression in multiple
stages and generates several tree data structures along the way, see Figure 1.
The new trace event outputs two of the trees to help users investigate logic or
performance issues. This is a great leap forward from the dark days of debugging
MDX expressions. Logical plan trees show the primitive operations that make up
the higher level user functions. The powerful yet sometimes mysterious automatic
cross-table filtering becomes explicit in logical plan trees. Properties related
to the <span class="SpellE">sparsity</span> of a scalar <span class="SpellE">subtree</span> tell you why DAX Formula Engine chooses one
execution plan over another. If poor performance is caused by the Formula
Engine, physical plan trees can help you locate the expensive sub-expressions
that caused the problem.</div>
<div class="MsoNormal">
<o:p> </o:p></div>
<div class="MsoNormal">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit63povo5yyUBila04MxBYKz1Zqhun7tw32Oml6b1NNng4jrfM_viqFgPQvugKUjHB_XXzRx-Ow7RkSQysBNJ0MXYcw6htlEohxvKZ3Ky34Uwz0O1RvKNkm8-UtW64hrhFmpGDzPNmqiM/s1600/QueryEvalStages.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="171" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit63povo5yyUBila04MxBYKz1Zqhun7tw32Oml6b1NNng4jrfM_viqFgPQvugKUjHB_XXzRx-Ow7RkSQysBNJ0MXYcw6htlEohxvKZ3Ky34Uwz0O1RvKNkm8-UtW64hrhFmpGDzPNmqiM/s400/QueryEvalStages.png" width="400" /></a></div>
<span style="mso-no-proof: yes;"><v:shapetype coordsize="21600,21600" filled="f" id="_x0000_t75" o:preferrelative="t" o:spt="75" path=" m@4@5 l@4@11@9@11@9@5 xe" stroked="f"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0 "></v:f><v:f eqn="sum @0 1 0 "></v:f><v:f eqn="sum 0 0 @1 "></v:f><v:f eqn="prod @2 1 2 "></v:f><v:f eqn="prod @3 21600 pixelWidth "></v:f><v:f eqn="prod @3 21600 pixelHeight "></v:f><v:f eqn="sum @0 0 1 "></v:f><v:f eqn="prod @6 1 2 "></v:f><v:f eqn="prod @7 21600 pixelWidth "></v:f><v:f eqn="sum @8 21600 0 "></v:f><v:f eqn="prod @7 21600 pixelHeight "></v:f><v:f eqn="sum @10 21600 0 "></v:f></v:formulas><v:path gradientshapeok="t" o:connecttype="rect" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype></span></div>
<div class="MsoNormal">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">Format of
the Query Plans<o:p></o:p></span></b></div>
<div class="MsoNormal">
<br />
Let’s first study the general structure and format common to
both types of plan trees. Send the following DAX query to the tabular <span class="SpellE">AdventureWorks</span> database:</div>
<pre class="code" style="margin-left: 15px;">define measure 'Internet Sales'[Total Sales Amount] = Sum([Sales Amount])
evaluate
filter(
addcolumns(
crossjoin(
values('Date'[Calendar Year]),
values('Product Category'[Product Category Name])
),
"Total Sales Amount", [Total Sales Amount]
),
not isblank([Total Sales Amount])
)
</pre>
<div class="MsoNormal">
<br />
When you execute this query, the logical plan tree and the
physical plan tree are shown in Figures 2 and 3 respectively.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFBK5r5vhksys4E6g9-VyePIo2Kd6OVajckAlPZ3uH06C5eP3NgU0KG0MJBZawSBn94g2ryA77ybKcRe1Y1v3MNisJH9npX5R5J2e_SvdauvoY3HqYqyRSmPcnoXwCof-bZPzzWbRpFSQ/s1600/LogOpTree.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="73" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFBK5r5vhksys4E6g9-VyePIo2Kd6OVajckAlPZ3uH06C5eP3NgU0KG0MJBZawSBn94g2ryA77ybKcRe1Y1v3MNisJH9npX5R5J2e_SvdauvoY3HqYqyRSmPcnoXwCof-bZPzzWbRpFSQ/s640/LogOpTree.png" width="640" /></a></div>
<span style="mso-no-proof: yes;"></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<o:p> </o:p></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisWaStTBkvbqPGASgI277OqZAx7E1kQBwFbBaDy6QA8Bw67il-zJS-QIM5hniaOtJY7KrD58Gy2EUX3JU_L2KOYQqrsf6tQz0rqzhYHvgksXCzPutAgjJgVg5b9H-apkWv0Fc3vL8azv0/s1600/PhyOpTree.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="130" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisWaStTBkvbqPGASgI277OqZAx7E1kQBwFbBaDy6QA8Bw67il-zJS-QIM5hniaOtJY7KrD58Gy2EUX3JU_L2KOYQqrsf6tQz0rqzhYHvgksXCzPutAgjJgVg5b9H-apkWv0Fc3vL8azv0/s640/PhyOpTree.png" width="640" /></a></div>
<o:p> </o:p></div>
<div class="MsoNormal">
As you can see, each plan tree is output as a multi-line
text. Each line represents a single operator node in the tree. The hierarchical
structure of a tree is maintained by indentation. Child nodes show up indented
below their parent nodes. Sibling nodes have the same level of indentation under
their parent. Each line begins with the name of the operator followed by a colon
and properties of the operator starting with the operator type.</div>
<div class="MsoNormal">
<o:p> </o:p></div>
<div class="MsoNormal">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG49QuaJJgno7fhyphenhyphen1BWyOA-nPLHMASmoG0GAefKyu1mFMieqmvdvxbTeLLDlAQVB2QK-TOGOhgJnbjOQ6nWaA7Pl2G6DhWCU_CPorBV_SWzvarKPp7fKwBcF0dBhvzbes7fcJ9nctDqF4/s1600/TextLineFormat.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="120" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG49QuaJJgno7fhyphenhyphen1BWyOA-nPLHMASmoG0GAefKyu1mFMieqmvdvxbTeLLDlAQVB2QK-TOGOhgJnbjOQ6nWaA7Pl2G6DhWCU_CPorBV_SWzvarKPp7fKwBcF0dBhvzbes7fcJ9nctDqF4/s640/TextLineFormat.png" width="640" /></a></div>
<span style="mso-no-proof: yes;"></span></div>
<div class="MsoNormal">
<o:p> </o:p></div>
<div class="MsoNormal">
<br />
<br />
<br />
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">Types of
Operators</span></b></div>
<div class="MsoNormal">
There are two types of logical plan nodes and two types of
physical plan nodes as shown in the table below. We’ll spend a lot more time in
future posts drilling into the details of various operators and their
properties.</div>
<div class="MsoNormal">
<o:p> </o:p></div>
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: currentColor; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;">
<tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;">
<td style="border: 1pt solid windowtext; mso-border-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 159.6pt;" valign="top" width="213"><div class="MsoNormal">
<b style="mso-bidi-font-weight: normal;">Plan
Type<o:p></o:p></b></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 159.6pt;" valign="top" width="213"><div class="MsoNormal">
<b style="mso-bidi-font-weight: normal;">Operator
Type<o:p></o:p></b></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 368.9pt;" valign="top" width="492"><div class="MsoNormal">
<b style="mso-bidi-font-weight: normal;">Description<o:p></o:p></b></div>
</td></tr>
<tr style="mso-yfti-irow: 1;">
<td rowspan="2" style="border-color: currentColor windowtext windowtext; border-style: none solid solid; border-width: medium 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 159.6pt;" valign="top" width="213"><div class="MsoNormal">
Logical Plan</div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 159.6pt;" valign="top" width="213"><div class="MsoNormal">
<span class="SpellE">ScaLogOp</span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 368.9pt;" valign="top" width="492"><div class="MsoNormal">
Scalar Logical Operator</div>
<div class="MsoNormal">
Outputs a scalar value of type numeric, string, Boolean,
etc.</div>
</td></tr>
<tr style="mso-yfti-irow: 2;">
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 159.6pt;" valign="top" width="213"><div class="MsoNormal">
<span class="SpellE">RelLogOp</span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 368.9pt;" valign="top" width="492"><div class="MsoNormal">
Relational Logical Operator</div>
<div class="MsoNormal">
Outputs a table of columns and rows.</div>
</td></tr>
<tr style="mso-yfti-irow: 3;">
<td rowspan="2" style="border-color: currentColor windowtext windowtext; border-style: none solid solid; border-width: medium 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 159.6pt;" valign="top" width="213"><div class="MsoNormal">
Physical Plan</div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 159.6pt;" valign="top" width="213"><div class="MsoNormal">
<span class="SpellE">LookupPhyOp</span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 368.9pt;" valign="top" width="492"><div class="MsoNormal">
Lookup Physical Operator</div>
<div class="MsoNormal">
Given a current row as input, calculates and returns a scalar
value.</div>
</td></tr>
<tr style="mso-yfti-irow: 4; mso-yfti-lastrow: yes;">
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 159.6pt;" valign="top" width="213"><div class="MsoNormal">
<span class="SpellE">IterPhyOp</span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 368.9pt;" valign="top" width="492"><div class="MsoNormal">
Iterator Physical Operator</div>
<div class="MsoNormal">
Given a current row as an optional input, returns a sequence
of rows.</div>
</td></tr>
</tbody></table>
<div class="MsoNormal">
<o:p> </o:p></div>
<div class="MsoNormal">
<br />
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">Number of
Trace Events per Query</span></b></div>
<div class="MsoNormal">
<br />
Each time the DAX Formula Engine is called to evaluate a DAX
expression, a pair of DAX Query Plan events are generated. Therefore, a DAX
query (Evaluate statement) triggers exactly two events: a logical plan event and
a physical plan event. But an MDX query may produce any number of pairs of
events depending on how many times the MDX Formula Engine has to call into the
DAX Formula Engine. At the time of this writing, DAX Formula Engine cannot call
back into MDX Formula Engine, although this may change in the future.</div>
<div class="MsoNormal">
<o:p> </o:p></div>
<div class="MsoNormal">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUOKXR-DPxmUdRvomrNHOcVtpG_K-NRf4yNoECTJ4qRI_p_J2nzGF7tGu87t_FA-MDLbYEOet_jeEiX2ELoQ-xGxXU-mF0xjYYxFcYNHLlgxAtMIzcxN7dSPOXN1DWXJCCF35TRSrzQSg/s1600/DAXEntryPoints.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="287" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUOKXR-DPxmUdRvomrNHOcVtpG_K-NRf4yNoECTJ4qRI_p_J2nzGF7tGu87t_FA-MDLbYEOet_jeEiX2ELoQ-xGxXU-mF0xjYYxFcYNHLlgxAtMIzcxN7dSPOXN1DWXJCCF35TRSrzQSg/s400/DAXEntryPoints.png" width="400" /></a></div>
<span style="mso-no-proof: yes;"></span></div>
<div class="MsoNormal">
<o:p> </o:p></div>
<div class="MsoNormal">
<br />
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">Event
Trigger Points</span></b></div>
<div class="MsoNormal">
<br />
Ideally, the DAX Formula Engine should generate both the
logical plan and the physical plan before any query execution happens so users
can capture the plans without being blocked by potentially long-running
operations. But this is not the case in the current implementation. Logical
plans are built in two stages. The first stage is quick and light-weight, but
the second stage may need to execute a portion of the tree therefore potentially
expensive. Unfortunately the logical plan event is fired after the second stage
is completed, so sometimes users may have to wait for certain time-consuming
operations to finish before they can capture the logical plan event. But in most
cases, constructing and simplifying a logical plan is a quick process. On the
other hand, building a physical plan can often involve expensive operations.
Although currently the trace event only shows two types of physical plan nodes:
lookup and iterator, there is actually a third type of plan node: spool. A spool
plan is when an operator materializes its result in memory by executing its
entire <span class="SpellE">subtree</span>. A physical plan tree may contain many
nodes built from spools, each of which requires partial execution of a <span class="SpellE">subtree</span> before the entire physical plan tree is fully
constructed. In particular, all leaf level nodes which require fetching data from the VertiPaq Engine currently always build spools to store VertiPaq results, therefore, users can see the physical plan event only after all VertiPaq queries have completed.</div>
<div class="MsoNormal">
<o:p> </o:p></div>
<div class="MsoNormal">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_bXMU60yD5B8pedQM9CwneYlBiCdsdG7GRpxOo-9VAOjkzelPfctfYcGFkBwubMgaGLWK3FK5iTDiFjPlZLaCy0tmjwiA22haRe1Qe-Sbv4DE6gKgdxD6EONfwfPHwfWI5IJ8pptGm-Y/s1600/TriggerPoints.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_bXMU60yD5B8pedQM9CwneYlBiCdsdG7GRpxOo-9VAOjkzelPfctfYcGFkBwubMgaGLWK3FK5iTDiFjPlZLaCy0tmjwiA22haRe1Qe-Sbv4DE6gKgdxD6EONfwfPHwfWI5IJ8pptGm-Y/s640/TriggerPoints.png" width="411" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<span style="mso-no-proof: yes;"></span></div>
<div class="MsoNormal">
<o:p> </o:p></div>
<div class="MsoNormal">
The new <b style="mso-bidi-font-weight: normal;">DAX Query
Plan</b> trace event can assist you in writing efficient DAX expressions and
troubleshooting problematic DAX behavior. How you use them is up to you, but
first you need to understand the information contained within the plans and how
to interpret it. Today we have gone over the basics such as types of plans,
format of text, types of plan nodes, and when and how frequently the events are
fired. Next time we are going one step further to examine the various properties
of plan nodes.</div>
<div class="MsoNormal">
<o:p> </o:p></div>
</div>Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com7tag:blogger.com,1999:blog-8486191632104654344.post-74122977497833675602011-11-15T17:08:00.001-08:002011-11-15T17:41:40.106-08:00Avoid Pitfalls of Fact Data Prefetching<style>
v\:* {behavior:url(#default#VML);}
o\:* {behavior:url(#default#VML);}
w\:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
</style>
<style>
<!--
/* Font Definitions */
@font-face
{font-family:Wingdings;
panose-1:5 0 0 0 0 0 0 0 0 0;
mso-font-charset:2;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:0 268435456 0 0 -2147483648 0;}
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;
mso-font-charset:0;
mso-generic-font-family:roman;
mso-font-pitch:variable;
mso-font-signature:-536870145 1107305727 0 0 415 0;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;
mso-font-charset:0;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:-520092929 1073786111 9 0 415 0;}
@font-face
{font-family:Tahoma;
panose-1:2 11 6 4 3 5 4 4 2 4;
mso-font-charset:0;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:-520081665 -1073717157 41 0 66047 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-unhide:no;
mso-style-qformat:yes;
mso-style-parent:"";
margin-top:0in;
margin-right:0in;
margin-bottom:10.0pt;
margin-left:0in;
line-height:115%;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:Calibri;
mso-fareast-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
p.MsoAcetate, li.MsoAcetate, div.MsoAcetate
{mso-style-noshow:yes;
mso-style-priority:99;
mso-style-link:"Balloon Text Char";
margin:0in;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:8.0pt;
font-family:"Tahoma","sans-serif";
mso-fareast-font-family:Calibri;
mso-fareast-theme-font:minor-latin;}
span.BalloonTextChar
{mso-style-name:"Balloon Text Char";
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-unhide:no;
mso-style-locked:yes;
mso-style-link:"Balloon Text";
mso-ansi-font-size:8.0pt;
mso-bidi-font-size:8.0pt;
font-family:"Tahoma","sans-serif";
mso-ascii-font-family:Tahoma;
mso-hansi-font-family:Tahoma;
mso-bidi-font-family:Tahoma;}
span.SpellE
{mso-style-name:"";
mso-spl-e:yes;}
span.GramE
{mso-style-name:"";
mso-gram-e:yes;}
.MsoChpDefault
{mso-style-type:export-only;
mso-default-props:yes;
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:Calibri;
mso-fareast-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
.MsoPapDefault
{mso-style-type:export-only;
margin-bottom:10.0pt;
line-height:115%;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;
mso-header-margin:.5in;
mso-footer-margin:.5in;
mso-paper-source:0;}
div.WordSection1
{page:WordSection1;}
-->
</style>
As mentioned in Chris Webb’s article <i style="mso-bidi-font-style: normal;"><a href="http://www.packtpub.com/article/query-performance-tuning-microsoft-analysis-services-part1"><span style="color: blue;">Query Performance Tuning in Microsoft Analysis Services</span></a></i> and SQL Server CAT team’s white paper <i style="mso-bidi-font-style: normal;"><a href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=661"><span style="color: blue;">SQLServer Best Practices Article: Identifying and Resolving MDX Query PerformanceBottlenecks in SQL Server 2005 Analysis Services</span></a></i>,
MDX Formula Engine (FE) may request more data from the Storage Engine (SE)
upfront so that following SE queries can be answered directly from the SE cache.
In order to retrieve the right amount of data, FE uses some clever heuristics
to construct the prefetch query. While the underlying design delivers great
performance most of the time, sometimes the resulting query prefetches too much
data. In this blog post I am going to show you a pathological case where a
prefetch query seems to completely ignore the slices in the original MDX query
thereby scan all partitions instead of just the needed ones. I will explain why
it happens so you understand what’s going on in the engine if you ever run into
such cases and deal with it accordingly.<br />
<div class="WordSection1">
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
To illustrate the problem, I am going to run a series of MDX
queries against the <span class="SpellE">AdventureWorks</span> sample database
for Microsoft SQL Server 2008R2. In between queries, I send <a href="http://geekswithblogs.net/darrengosbell/archive/2007/08/30/SSAS-Query-Performance-Tuning-Whitepaper.aspx"><span style="color: blue;">ClearCache commands</span></a>
to eliminate inter-query interference. For each MDX query, we are going to
observe the sequence of SE queries through the <b style="mso-bidi-font-weight: normal;">Query Subcube Verbose</b> profiler trace events. Instead of showing the
complete output of <b style="mso-bidi-font-weight: normal;">Query Subcube Verbose
</b>events, I am going to extract only those attributes in the [Date] dimension
which are relevant to our discussion. As well known in the MDX community, Analysis
Services engine internally uses subcubes to represent queries, therefore I will
use the terms query and subcube interchangeably throughout the post.</div>
<div class="MsoNormal">
Now, let’s run our first MDX query to retrieve the values of
measure [Internet Sales Amount] for all days in January 2007.</div>
<div class="MsoNormal">
<b style="mso-bidi-font-weight: normal;">Query 1:<o:p></o:p></b></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">// January
2007<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">select</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> [Internet Sales Amount] on 0,<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">head(</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">descendants([Date].[Calendar].[Calendar Year].&[2007],
[Date].[Calendar].[Date]), 31) on 1<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">from</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> [Adventure Works]<o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Since measure [Internet Sales Amount] is defined as a
measure expression, there are three <b style="mso-bidi-font-weight: normal;">Query
Subcube Verbose</b> events, one for the [Exchange Rates] measure group, two for
the [Internet Sales] measure group, although only one of them hits the
partitions, the other is just an artifact of measure expression evaluation.</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgt-h8GbicL293kM66CQ3YS-vAy17wXjG9KsZzdNrpAQfuNsCKqwirt-MdfLAp9VsyY_cXMM5izgAPCMl_46rz8iX7Yt9nxG-s5_0qsbqC1dNalnrIvwn6b6WRjKnueK5TqN3-Qj7G2mP0/s1600/Q1ProfilerTrace.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="92" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgt-h8GbicL293kM66CQ3YS-vAy17wXjG9KsZzdNrpAQfuNsCKqwirt-MdfLAp9VsyY_cXMM5izgAPCMl_46rz8iX7Yt9nxG-s5_0qsbqC1dNalnrIvwn6b6WRjKnueK5TqN3-Qj7G2mP0/s640/Q1ProfilerTrace.png" width="640" /></a></div>
<div class="MsoNormal">
<span style="mso-no-proof: yes;"><v:shapetype coordsize="21600,21600" filled="f" id="_x0000_t75" o:preferrelative="t" o:spt="75" path="m@4@5l@4@11@9@11@9@5xe" stroked="f">
<v:stroke joinstyle="miter">
<v:formulas>
<v:f eqn="if lineDrawn pixelLineWidth 0">
<v:f eqn="sum @0 1 0">
<v:f eqn="sum 0 0 @1">
<v:f eqn="prod @2 1 2">
<v:f eqn="prod @3 21600 pixelWidth">
<v:f eqn="prod @3 21600 pixelHeight">
<v:f eqn="sum @0 0 1">
<v:f eqn="prod @6 1 2">
<v:f eqn="prod @7 21600 pixelWidth">
<v:f eqn="sum @8 21600 0">
<v:f eqn="prod @7 21600 pixelHeight">
<v:f eqn="sum @10 21600 0">
</v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:formulas>
<v:path gradientshapeok="t" o:connecttype="rect" o:extrusionok="f">
<o:lock aspectratio="t" v:ext="edit">
</o:lock></v:path></v:stroke></v:shapetype></span></div>
<div class="MsoNormal">
Here are the attributes corresponding to levels in the
[Calendar] hierarchy extracted from the trace events:</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Dimension 7 [Date] (0 * 8 0 6 0 0 0 0 0
0 20 4 0 0 0 0 0 0 0 0)</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Date]:*</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Quarter]<span class="GramE">:[</span>Q1
CY 2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Semester]<span class="GramE">:[</span>H1
CY 2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Month Name]<span class="GramE">:[</span>January
2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Year]<span class="GramE">:[</span>CY
2007]</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
The SE query asks for all days in January 2007, which match
exactly the days listed on Axis 1 of the MDX query, with the added benefit of
not listing each day individually. There is no prefetch query in this case
which makes sense as the original query is asking for all days in January 2007
that matches exactly the SE query.</div>
<div class="MsoNormal">
Now let’s add one more day to the query.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">Query 2:<o:p></o:p></span></b></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">// January
2007 + February 1 2007<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">select</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> [Internet Sales Amount] on 0,<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">head(</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">descendants([Date].[Calendar].[Calendar Year].&[2007],
[Date].[Calendar].[Date]), 32) on 1<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">from</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> [Adventure Works]<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
From the
captured profiler trace below</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzC8KJQc9vzCfMhj4UYH-CQcy-Q9pIgIFOI8x_TJ-pyGM6gsLInC0EIl8vfSh0-F-BYJRDToV5ChDjGHZ7bVxHhD012HVm3hfHc08JkN8F0zlaYBapIodBpa2eIeAE3My8Jr2MFbfsW00/s1600/Q2ProfilerTrace.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="122" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzC8KJQc9vzCfMhj4UYH-CQcy-Q9pIgIFOI8x_TJ-pyGM6gsLInC0EIl8vfSh0-F-BYJRDToV5ChDjGHZ7bVxHhD012HVm3hfHc08JkN8F0zlaYBapIodBpa2eIeAE3My8Jr2MFbfsW00/s640/Q2ProfilerTrace.png" width="640" /></a></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<o:p> </o:p><o:p> </o:p></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
You can
extract the following information form the three queries sent to the [Internet
Sales] measure group:</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Non-cache data</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Dimension 7 [Date] (0 * 8 0 6 0 0 0 0 0
0 20 4 0 0 0 0 0 0 0 0)</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Date]:*</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Quarter]<span class="GramE">:[</span>Q1
CY 2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Semester]<span class="GramE">:[</span>H1
CY 2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Month Name]<span class="GramE">:[</span>January
2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Year]<span class="GramE">:[</span>CY
2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Non-cache data</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Dimension 7 [Date] (0 * 8 0 6 0 0 0 0 0
0 21 4 0 0 0 0 0 0 0 0)</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Date]:*</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Quarter]<span class="GramE">:[</span>Q1
CY 2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Semester]<span class="GramE">:[</span>H1
CY 2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Month Name]<span class="GramE">:[</span>February
2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Year]<span class="GramE">:[</span>CY
2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Cache data</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Dimension 7 [Date] (0 582 8 0 6 0 0 0 0
0 0 21 4 0 0 0 0 0 0 0 0)</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Date]<span class="GramE">:[</span>February
1, 2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Quarter]<span class="GramE">:[</span>Q1
CY 2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Semester]<span class="GramE">:[</span>H1
CY 2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Month Name]<span class="GramE">:[</span>February
2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Year]<span class="GramE">:[</span>CY
2007]</div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Again there is no prefetch query for January 2007 but FE
does prefetch all days in February 2007 first before getting the value of
February 1, 2007 from cached data.</div>
<div class="MsoNormal">
Now let’s add one more day again to the query.</div>
<div class="MsoNormal">
<b style="mso-bidi-font-weight: normal;">Query 3:<o:p></o:p></b></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">// January
2007 + February 1 2007 + February 2 2007<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">select</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> [Internet Sales Amount] on 0,<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">head(</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">descendants([Date].[Calendar].[Calendar Year].&[2007],
[Date].[Calendar].[Date]), 33) on 1<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">from</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> [Adventure Works]<o:p></o:p></span></div>
<div class="MsoNormal">
<br /></div>
<div class="MsoNormal">
Below is the profiler trace events and relevant information
extracted from them:</div>
<div class="MsoNormal">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEss0quFZPRHmQvSDG4MVUv2_LbaLilogq7Tyo8fVRsQFxCFQnAM5kvqZp7K6wYlD7JA28gN8ifjQStI_pdBAudQ0Y2MLT-O9bP7IBnZHiSz0krObXdSH9MgUqYokKh7i6NIb0vJpheyw/s1600/Q3ProfilerTrace.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="156" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEss0quFZPRHmQvSDG4MVUv2_LbaLilogq7Tyo8fVRsQFxCFQnAM5kvqZp7K6wYlD7JA28gN8ifjQStI_pdBAudQ0Y2MLT-O9bP7IBnZHiSz0krObXdSH9MgUqYokKh7i6NIb0vJpheyw/s640/Q3ProfilerTrace.png" width="640" /></a></div>
<div class="MsoNormal">
<span style="mso-no-proof: yes;"></span></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Non-cache data:</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Dimension 7 [Date] (0 * * 0 * 0 0 0 0 0
0 * * 0 0 0 0 0 0 0 0)</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Date]:*</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Quarter]:*</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Semester]:*</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Month Name]:*</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Year]:*</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Cache data:</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Dimension 7 [Date] (0 * 8 0 6 0 0 0 0 0
0 20 4 0 0 0 0 0 0 0 0)</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Date]:*</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Quarter]<span class="GramE">:[</span>Q1
CY 2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Semester]<span class="GramE">:[</span>H1
CY 2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Month Name]<span class="GramE">:[</span>January
2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Year]<span class="GramE">:[</span>CY
2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Cache data:</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Dimension 7 [Date] (0 + * 0 * 0 0 0 0 0
0 * * 0 0 0 0 0 0 0 0)</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Date]:+</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Quarter]:*</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Semester]:*</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Month Name]:*</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Year]:*</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
One <span class="SpellE"><span class="GramE"><b style="mso-bidi-font-weight: normal;">EventSubclass</b></span></span><span class="GramE"><b style="mso-bidi-font-weight: normal;"> <span style="mso-spacerun: yes;"> </span>=</b></span><b style="mso-bidi-font-weight: normal;"> Non-Cache data</b> query prefetches fact data into SE cache which is
used to answer the subsequent two SE queries shown as <span class="SpellE"><b style="mso-bidi-font-weight: normal;">EventSubclass</b></span><b style="mso-bidi-font-weight: normal;"><span style="mso-spacerun: yes;"> </span>=
Cache data</b>, one for all days in January 2007, the other for the first two
days of February 2007. But why did the prefetch query ask for data for all
dates? Why did we lose all slices in the [Date] dimension? This is really bad
as it would have caused all partitions to be scanned. The answer lies in the
imprecise nature of the algorithm used to construct the prefetch subcube.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
In order to
build the prefetch SE subcube, FE keeps track of all relevant MDX sets in a stack-like
data structure called Sonar registry. Later on each MDX set in the Sonar
registry is used to build a collection of Sonar subcubes. <span class="SpellE">Perfmon</span>
counter <b style="mso-bidi-font-weight: normal;">MDX\Total Sonar subcubes</b>
displays the total number of Sonar subcubes generated inside FE.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_sWkKBQfX4DiTtoFLb-w6-FumXWMOUHhu8bZ2aIiTOR4KAJc3TGQpXwGw5qJpS-IEtReLYjg3PkRjxGyvWyJTycR9uX68eAMRhyphenhyphenHkBZ7FToFW4mCVm9TNuVnBu5pQsWUsAnuUEMveHo4/s1600/Perfmon.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="38" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_sWkKBQfX4DiTtoFLb-w6-FumXWMOUHhu8bZ2aIiTOR4KAJc3TGQpXwGw5qJpS-IEtReLYjg3PkRjxGyvWyJTycR9uX68eAMRhyphenhyphenHkBZ7FToFW4mCVm9TNuVnBu5pQsWUsAnuUEMveHo4/s640/Perfmon.png" width="640" /></a></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
By default,
the conversion from an MDX set to its collection of Sonar subcubes is not a
precise process. The resulting Sonar subcubes will cover the original MDX set
but may include additional members on some attributes. The <b style="mso-bidi-font-weight: normal;">Cache Ratio</b> connection string property controls how a Sonar subcube
attribute is expanded to include more members than what the original set
contains. The actual algorithm is very complex. I am only going to show here a
greatly simplified version that illustrates the main idea of the algorithm.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<b style="mso-bidi-font-weight: normal;">Algorithm 1: Build Sonar subcubes from an
MDX set<o:p></o:p></b></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
Input: an
MDX set <i style="mso-bidi-font-style: normal;">S</i>, for simplicity, assume <i style="mso-bidi-font-style: normal;">S</i> is single-grained</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br />
For each hierarchy
<i style="mso-bidi-font-style: normal;">H</i> in <i style="mso-bidi-font-style: normal;">S</i></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Since <i style="mso-bidi-font-style: normal;">S</i> is single-grained, let <span class="SpellE"><i style="mso-bidi-font-style: normal;">L</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">s</span></sub></i></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> </span>be the
level of <i style="mso-bidi-font-style: normal;">H</i> where members of <i style="mso-bidi-font-style: normal;">S</i> reside</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
For each level <i style="mso-bidi-font-style: normal;">L</i> in <i style="mso-bidi-font-style: normal;">H</i> starting from the
topmost level down to <span class="SpellE"><i style="mso-bidi-font-style: normal;">L</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">s</span></sub></i></span></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 1in;">
Identify all members on <i style="mso-bidi-font-style: normal;">L</i> with good coverage of <i style="mso-bidi-font-style: normal;">S</i></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 1in;">
A member <i style="mso-bidi-font-style: normal;">M</i> has good coverage of <i style="mso-bidi-font-style: normal;">S</i>
if the ratio of the number of its descendants in <i style="mso-bidi-font-style: normal;">S</i> to the number of all its descendants on level <span class="SpellE"><i style="mso-bidi-font-style: normal;">L</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">s</span></sub></i></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> </span><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;">is greater
than or equal to</span> the Cache Ratio</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 1in;">
Add <i style="mso-bidi-font-style: normal;">M</i> to the list of slicers on level <i style="mso-bidi-font-style: normal;">L</i></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
For each level with a nonempty list of
slicers</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 1in;">
Create a Sonar subcube with granularities
on attributes corresponding to the levels of <i style="mso-bidi-font-style: normal;">H</i> from the topmost level down to <span class="SpellE"><i style="mso-bidi-font-style: normal;">L</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">s</span></sub></i></span></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 1in;">
Apply the list of slicers to the
subcube</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br />
Output: the
collection of generated Sonar subcubes</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
First, apply
<b style="mso-bidi-font-weight: normal;">Algorithm 1</b> to the [Calendar] set in
<b style="mso-bidi-font-weight: normal;">Query 1<o:p></o:p></b></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">head(</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">descendants([Date].[Calendar].[Calendar
Year].&[2007], [Date].[Calendar].[Date]), 31)<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span class="GramE">you</span> get the following sequence of slices encoded in internal
data IDs and eventually FE finds a single good cover slice on the month level.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Sonar [Calendar] [1 * * * * *] ratio:
31/1188</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 * * * *] ratio: 31/365</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 6 * * *] ratio: 31/181</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 6 8 * *] ratio: 31/90</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 6 8 20 *] ratio: 31/31 <span style="font-family: Wingdings; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-char-type: symbol; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-symbol-font-family: Wingdings;"><span style="mso-char-type: symbol; mso-symbol-font-family: Wingdings;">ß</span></span> good cover</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
The
resulting Sonar subcube is</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<b style="mso-bidi-font-weight: normal;">Sonar
Subcube 1<o:p></o:p></b></div>
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: currentColor; margin-left: 0.5in; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;">
<tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;">
<td style="border: 1pt solid windowtext; mso-border-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.95in;" valign="top" width="91"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Year<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1.25in;" valign="top" width="120"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Semester<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Quarter<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 67.5pt;" valign="top" width="90"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Month Name<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.5in;" valign="top" width="48"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Date<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 1; mso-yfti-lastrow: yes;">
<td style="border-color: currentColor windowtext windowtext; border-style: none solid solid; border-width: medium 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.95in;" valign="top" width="91"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1.25in;" valign="top" width="120"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">H1 CY 2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Q1 CY 2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 67.5pt;" valign="top" width="90"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">January 2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.5in;" valign="top" width="48"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">*<o:p></o:p></span></div>
</td>
</tr>
</tbody></table>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
Here and in
the following I only show the important attributes in the Sonar subcube which
correspond to levels of the [Calendar] hierarchy. Next, apply <b style="mso-bidi-font-weight: normal;">Algorithm 1</b> to the [Calendar] set in <b style="mso-bidi-font-weight: normal;">Query 2<o:p></o:p></b></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">head(</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">descendants([Date].[Calendar].[Calendar
Year].&[2007], [Date].[Calendar].[Date]), 32)<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
FE finds two
good cover slices, one on the month level and the other on the date level.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Sonar [Calendar] [1 * * * * *] ratio:
32/1188</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 * * * *] ratio: 32/365</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 6 * * *] ratio: 32/181</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 6 8 * *] ratio: 32/90</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 6 8 20 *] ratio: 31/31 <span style="font-family: Wingdings; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-char-type: symbol; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-symbol-font-family: Wingdings;"><span style="mso-char-type: symbol; mso-symbol-font-family: Wingdings;">ß</span></span> good cover</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 6 8 21 *] ratio: 1/28</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 6 8 21 582] ratio: 1/1 <span style="font-family: Wingdings; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-char-type: symbol; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-symbol-font-family: Wingdings;"><span style="mso-char-type: symbol; mso-symbol-font-family: Wingdings;">ß</span></span> good cover</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
The two
Sonar subcubes created are:</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<b style="mso-bidi-font-weight: normal;">Sonar
Subcube 2.1<o:p></o:p></b></div>
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: currentColor; margin-left: 0.5in; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;">
<tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;">
<td style="border: 1pt solid windowtext; mso-border-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.95in;" valign="top" width="91"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Year<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1.25in;" valign="top" width="120"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Semester<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Quarter<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 67.5pt;" valign="top" width="90"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Month Name<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.5in;" valign="top" width="48"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Date<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 1; mso-yfti-lastrow: yes;">
<td style="border-color: currentColor windowtext windowtext; border-style: none solid solid; border-width: medium 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.95in;" valign="top" width="91"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1.25in;" valign="top" width="120"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">H1 CY 2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Q1 CY 2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 67.5pt;" valign="top" width="90"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">January 2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.5in;" valign="top" width="48"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">*<o:p></o:p></span></div>
</td>
</tr>
</tbody></table>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<b style="mso-bidi-font-weight: normal;">Sonar
Subcube 2.2<o:p></o:p></b></div>
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: currentColor; margin-left: 0.5in; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;">
<tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;">
<td style="border: 1pt solid windowtext; mso-border-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.95in;" valign="top" width="91"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Year<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1.25in;" valign="top" width="120"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Semester<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Quarter<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Month Name<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 81pt;" valign="top" width="108"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Date<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 1; mso-yfti-lastrow: yes;">
<td style="border-color: currentColor windowtext windowtext; border-style: none solid solid; border-width: medium 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.95in;" valign="top" width="91"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1.25in;" valign="top" width="120"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">H1 CY 2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Q1 CY 2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">February
2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 81pt;" valign="top" width="108"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">February 1,
2007<o:p></o:p></span></div>
</td>
</tr>
</tbody></table>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
Finally,
apply <b style="mso-bidi-font-weight: normal;">Algorithm 1</b> to the [Calendar]
set in <b style="mso-bidi-font-weight: normal;">Query 3<o:p></o:p></b></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">head(</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">descendants([Date].[Calendar].[Calendar
Year].&[2007], [Date].[Calendar].[Date]), 33)<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
FE finds
three good cover slices, one on the month level and two on the date level.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Sonar [Calendar] [1 * * * * *] ratio:
33/1188</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 * * * *] ratio: 33/365</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 6 * * *] ratio: 33/181</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 6 8 * *] ratio: 33/90</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 6 8 20 *] ratio: 31/31 <span style="font-family: Wingdings; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-char-type: symbol; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-symbol-font-family: Wingdings;"><span style="mso-char-type: symbol; mso-symbol-font-family: Wingdings;">ß</span></span> good cover</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 6 8 21 *] ratio: 2/28</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 6 8 21 582] ratio: 1/1 <span style="font-family: Wingdings; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-char-type: symbol; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-symbol-font-family: Wingdings;"><span style="mso-char-type: symbol; mso-symbol-font-family: Wingdings;">ß</span></span> good cover</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<span style="mso-spacerun: yes;">
</span>Sonar [Calendar] [1 4 6 8 21 583] ratio: 1/1 <span style="font-family: Wingdings; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-char-type: symbol; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-symbol-font-family: Wingdings;"><span style="mso-char-type: symbol; mso-symbol-font-family: Wingdings;">ß</span></span> good cover</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
Again, FE
created two Sonar subcubes.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<b style="mso-bidi-font-weight: normal;">Sonar
Subcube 3.1<o:p></o:p></b></div>
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: currentColor; margin-left: 0.5in; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;">
<tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;">
<td style="border: 1pt solid windowtext; mso-border-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.95in;" valign="top" width="91"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Year<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1.25in;" valign="top" width="120"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Semester<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Quarter<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 67.5pt;" valign="top" width="90"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Month Name<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.5in;" valign="top" width="48"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Date<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 1; mso-yfti-lastrow: yes;">
<td style="border-color: currentColor windowtext windowtext; border-style: none solid solid; border-width: medium 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.95in;" valign="top" width="91"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1.25in;" valign="top" width="120"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">H1 CY 2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Q1 CY 2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 67.5pt;" valign="top" width="90"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">January 2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.5in;" valign="top" width="48"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">*<o:p></o:p></span></div>
</td>
</tr>
</tbody></table>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<b style="mso-bidi-font-weight: normal;">Sonar
Subcube 3.2<o:p></o:p></b></div>
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: currentColor; margin-left: 0.5in; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;">
<tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;">
<td style="border: 1pt solid windowtext; mso-border-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.95in;" valign="top" width="91"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Year<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1.25in;" valign="top" width="120"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar Semester<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Quarter<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Month Name<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 31.5pt;" valign="top" width="42"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Date<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 1; mso-yfti-lastrow: yes;">
<td style="border-color: currentColor windowtext windowtext; border-style: none solid solid; border-width: medium 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.95in;" valign="top" width="91"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">*<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1.25in;" valign="top" width="120"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">*<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">*<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">*<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 31.5pt;" valign="top" width="42"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">+<o:p></o:p></span></div>
</td>
</tr>
</tbody></table>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
Note that <b style="mso-bidi-font-weight: normal;">Sonar Subcube 2.2</b> retains slices on all
levels of the [Calendar] hierarchy while <b style="mso-bidi-font-weight: normal;">Sonar
Subcube 3.2</b> only has a slice on the lowest level of the [Calendar]
hierarchy. This is an artifact of the current implementation. When multiple
covering members of a hierarchy are added to a Sonar subcube, only a single
slice is created at the lowest level of the hierarchy.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
FE uses
Sonar subcubes in several different places, including constructing a larger
evaluation node when FE is executing in cell-by-cell mode. In the simple case
where an MDX query can be answered directly from SE, Sonar subcubes are used to
construct SE queries.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<b style="mso-bidi-font-weight: normal;">Algorithm 2: Evaluate cell values<o:p></o:p></b></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
Input: a
cell iterator and the current Sonar registry</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
For each
cell <i style="mso-bidi-font-style: normal;">C<o:p></o:p></i></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Find the Sonar subcube <i style="mso-bidi-font-style: normal;">S</i> that contains <i style="mso-bidi-font-style: normal;">C</i></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Build an evaluation node <i style="mso-bidi-font-style: normal;">E </i>for <i style="mso-bidi-font-style: normal;">S</i></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Execute <i style="mso-bidi-font-style: normal;">E</i>. In the simplest case, create SE subcube <i style="mso-bidi-font-style: normal;">S<sub>SE</sub></i> from <i style="mso-bidi-font-style: normal;">S</i> and
send <i style="mso-bidi-font-style: normal;">S<sub>SE</sub></i> to SE.</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Lookup value of <i style="mso-bidi-font-style: normal;">C</i> from cached result in <i style="mso-bidi-font-style: normal;">E</i></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
Output: cell
values</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
Another
usage of Sonar subcubes is to build a prefetch subcube from a given SE query
subcube. The full algorithm is again very complex with exceptions and special
handling of arbitrary shapes or unary operators, etc. Here I include a
simplified version to illustrate the essence of the algorithm:</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<b style="mso-bidi-font-weight: normal;">Algorithm 3: Build a prefetch subcube for a
query subcube<o:p></o:p></b></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
Input: a SE query
subcube <span class="SpellE"><i style="mso-bidi-font-style: normal;">S</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">query</span></sub></i></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> and the current
Sonar registry<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
Initialize
the prefetch subcube <span class="SpellE"><i style="mso-bidi-font-style: normal;">S</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">prefetch</span></sub></i></span> as
a clone of <span class="SpellE"><i style="mso-bidi-font-style: normal;">S</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">query</span></sub></i></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">,</span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span class="GramE">For each Sonar</span> subcube <span class="SpellE"><i style="mso-bidi-font-style: normal;">S</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">sonar</span></sub></i></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> in the
Sonar registry</span></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
For each attribute <span class="SpellE"><i style="mso-bidi-font-style: normal;">A</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">prefetch</span></sub></i></span>
in <span class="SpellE"><i style="mso-bidi-font-style: normal;">S</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">prefetch</span></sub></i></span></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 1in;">
Find the corresponding attribute <span class="SpellE"><i style="mso-bidi-font-style: normal;">A</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">sonar</span></sub></i></span> in <span class="SpellE"><i style="mso-bidi-font-style: normal;">S</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">sonar</span></sub></i></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 1in;">
Skip <span class="SpellE"><i style="mso-bidi-font-style: normal;">A</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">sonar</span></sub></i></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> if it is
not a granularity <span class="GramE">attribute</span><o:p></o:p></span></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 1in;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">If </span><span class="SpellE"><i style="mso-bidi-font-style: normal;">A</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">prefetch</span></sub></i></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> is a
granularity attribute<o:p></o:p></span></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 1.5in;">
If the slice of <span class="SpellE"><i style="mso-bidi-font-style: normal;">A</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">sonar</span></sub></i></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> is a
superset of the slice of </span><span class="SpellE"><i style="mso-bidi-font-style: normal;">A</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">prefetch</span></sub></i></span><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><o:p></o:p></span></sub></i></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 2in;">
Copy the slice of <span class="SpellE"><i style="mso-bidi-font-style: normal;">A</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">sonar</span></sub></i></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> to </span><span class="SpellE"><i style="mso-bidi-font-style: normal;">A</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">prefetch</span></sub></i></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><o:p></o:p></span></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 1in;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">Else<o:p></o:p></span></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 1.5in;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">If the slice of </span><span class="SpellE"><i style="mso-bidi-font-style: normal;">A</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">sonar</span></sub></i></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> includes all members<o:p></o:p></span></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 2in;">
<span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">Make </span><span class="SpellE"><i style="mso-bidi-font-style: normal;">A</i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">prefetch</span></sub></i></span><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> <span class="GramE">a granularity attribute</span><o:p></o:p></span></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 2in;">
</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
Output: <span class="SpellE"><i style="mso-bidi-font-style: normal;"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">S</span></i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">prefetch</span></sub></i></span> if it is different from <span class="SpellE"><i style="mso-bidi-font-style: normal;"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">S</span></i><i style="mso-bidi-font-style: normal;"><sub><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">query</span></sub></i></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
In <b style="mso-bidi-font-weight: normal;">Query 1</b>, <b style="mso-bidi-font-weight: normal;">Sonar Subcube 1</b> is equivalent to the SE query subcube therefore no
prefetch subcube is needed. In <b style="mso-bidi-font-weight: normal;">Query 2</b>,
the first SE query subcube matches <b style="mso-bidi-font-weight: normal;">Sonar
Subcube 2.1</b> so again no prefetch subcube is needed. But the second SE query
would copy the * from [Date] in <b style="mso-bidi-font-weight: normal;">Sonar
Subcube 2.1 </b>therefore produce a prefetch subcube that fetches all days in
February. The * in <b style="mso-bidi-font-weight: normal;">Sonar Subcube 2.1 </b>really
means all days in January 2007 but <b style="mso-bidi-font-weight: normal;">Algorithm
3</b> treats each attribute independently and is oblivious to the fact that
[Date]:* is cross-filtered by slices on other attributes. But the end result of
prefetching all days in February 2007 isn’t too bad.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<b style="mso-bidi-font-weight: normal;">Prefetch
Subcube 1<o:p></o:p></b></div>
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: currentColor; margin-left: 0.5in; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;">
<tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;">
<td style="border: 1pt solid windowtext; mso-border-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.95in;" valign="top" width="91"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Year<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1.25in;" valign="top" width="120"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Semester<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Quarter<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Month Name<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 31.5pt;" valign="top" width="42"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Date<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 1; mso-yfti-lastrow: yes;">
<td style="border-color: currentColor windowtext windowtext; border-style: none solid solid; border-width: medium 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.95in;" valign="top" width="91"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1.25in;" valign="top" width="120"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">H1 CY 2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Q1 CY 2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">February
2007<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 31.5pt;" valign="top" width="42"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">*<o:p></o:p></span></div>
</td>
</tr>
</tbody></table>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
But when we
come to <b style="mso-bidi-font-weight: normal;">Query 3</b>, there is a * on
each attribute from either <b style="mso-bidi-font-weight: normal;">Sonar Subcube
3.1</b> or <b style="mso-bidi-font-weight: normal;">Sonar Subcube 3.2</b>, we end
up with a prefetch subcube that has * on all its attributes.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
<b style="mso-bidi-font-weight: normal;">Prefetch
Subcube 2<o:p></o:p></b></div>
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-collapse: collapse; border: currentColor; margin-left: 0.5in; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;">
<tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;">
<td style="border: 1pt solid windowtext; mso-border-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.95in;" valign="top" width="91"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Year<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1.25in;" valign="top" width="120"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Semester<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Calendar
Quarter<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Month Name<o:p></o:p></span></div>
</td>
<td style="border-color: windowtext windowtext windowtext currentColor; border-style: solid solid solid none; border-width: 1pt 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 31.5pt;" valign="top" width="42"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">Date<o:p></o:p></span></div>
</td>
</tr>
<tr style="mso-yfti-irow: 1; mso-yfti-lastrow: yes;">
<td style="border-color: currentColor windowtext windowtext; border-style: none solid solid; border-width: medium 1pt 1pt; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 0.95in;" valign="top" width="91"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">*<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1.25in;" valign="top" width="120"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">*<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">*<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 1in;" valign="top" width="96"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">*<o:p></o:p></span></div>
</td>
<td style="border-color: currentColor windowtext windowtext currentColor; border-style: none solid solid none; border-width: medium 1pt 1pt medium; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding: 0in 5.4pt; width: 31.5pt;" valign="top" width="42"><div class="MsoNormal" style="line-height: normal; margin-bottom: 0pt;">
<span style="font-size: 10pt; mso-bidi-font-size: 11.0pt;">*<o:p></o:p></span></div>
</td>
</tr>
</tbody></table>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
Nowadays we
are seeing more and more implementation of systems with multiple terabytes of
data in Analysis Services. The above example of overly aggressive prefetching
of fact data is unacceptable in such environments. You can disable prefetching
altogether by setting connection string property <b style="mso-bidi-font-weight: normal;">Disable Prefetch Facts</b>=true or you can play with the <b style="mso-bidi-font-weight: normal;">Cache Ratio</b> connection string property to
influence the Sonar subcubes generated by FE. But either approach is likely to
have negative performance impact that would require a lot of testing to confirm
their overall benefit against a certain query set. If you can control the types
of queries in your deployment, it is better to replace queries that fall into
this pitfall with ones that produce good Sonar subcubes in the default settings.
Using our example, since we know that there are 90 days in the first quarter
and the default <b style="mso-bidi-font-weight: normal;">Cache Ratio</b> is 0.5, we
can simply ask for 45 days instead of 33 days to produce a single good cover at
quarter level.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<b style="mso-bidi-font-weight: normal;">Query 4:<o:p></o:p></b></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">// January
2007 + February 1-14 2007<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">select</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> [Internet Sales Amount] on 0,<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">head(</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">descendants([Date].[Calendar].[Calendar Year].&[2007],
[Date].[Calendar].[Date]), 45) on 1<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<span class="GramE"><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;">from</span></span><span style="font-size: 10pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"> [Adventure Works]<o:p></o:p></span></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<o:p> </o:p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLkkIlQ-FEDLCtSGKnPOudLhVtDSrpd9FAOXn5fW9VBu4jgXPTCvfugDhrvKBkOlKytIVmLobG1ioE_GJq6RWPGKAv6G5DeT8Q0e_vsusmouvIcrThlEzSqC0LcydKWiELh3kEHZTzaB4/s1600/Q4ProfilerTrace.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="96" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLkkIlQ-FEDLCtSGKnPOudLhVtDSrpd9FAOXn5fW9VBu4jgXPTCvfugDhrvKBkOlKytIVmLobG1ioE_GJq6RWPGKAv6G5DeT8Q0e_vsusmouvIcrThlEzSqC0LcydKWiELh3kEHZTzaB4/s640/Q4ProfilerTrace.png" width="640" /></a></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
The captured
profiler trace confirmed our conjecture as it shows a single SE query to the
[Internet Sales] measure group to retrieve all days in the first quarter of
2007.</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
Dimension 7 [Date] (0 * 8 0 6 0 0 0 0 0
0 * 4 0 0 0 0 0 0 0 0)</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Date]:*</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Quarter]<span class="GramE">:[</span>Q1
CY 2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Semester]<span class="GramE">:[</span>H1
CY 2007]</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Month Name]:*</div>
<div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;">
[Calendar Year]<span class="GramE">:[</span>CY
2007]</div>
<div class="MsoNormal" style="margin-bottom: 0pt;">
<br /></div>
</div>Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com3tag:blogger.com,1999:blog-8486191632104654344.post-80762267455095257232011-10-22T17:26:00.000-07:002011-10-22T17:26:19.271-07:00Three Strategies of Evaluating the MDX Aggregate Function<span style="font-family: Calibri;">In the past two months, the Analysis Services development team was preoccupied with wrapping up SQL Server Denali development. I was racing against time to put finishing touches on some exciting new DAX features that I will write in more details once Denali goes public. It didn’t help that PASS 2011 fell on the same week that developers were allowed to make a final batch of code changes before the checkin bar would be lifted prohibitively high. All the flurry of activity forced me to postpone writing blogs on a couple of topics queued up over the past year. Now that things have quieted down a lot on the Denali front, the development team immediately switched gear to work on the next batch of important features requested by many customers, like supporting DAX queries against multidimensional cubes. Over the next few months before Denali hits the stores, I’ll try to finish up several MDX topics that I had put on the backburner due to Denali crunch time.<o:p></o:p></span> <br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Before I get to the main subject of today’s post, I’d like to say a few words on PASS Summit 2011 that happened here at Seattle about a week ago. AS team, and Microsoft at large, always encourages product developers to interact with customers through venues like PASS so that we get a chance to see firsthand how the products we have built impact people’s lives. I was gratified to see that <a href="http://www.powerpivotblog.nl/"><span style="color: blue;">Kasper</span></a> received a round of applause when he gave the audience a glimpse of DAX query plans, a feature I personally fought very hard to be included in Denali. Obviously the room was filled with MDX users who have waited for years an MDX query plan feature. One MVP told me that she thinks MDX is a beautiful language. That was the first time I heard the word <i style="mso-bidi-font-style: normal;">beautiful</i> to be associated with MDX, what I had previoulsy heard were all in line with hard or difficult. I have also heard touching stories about how brothers both turned into MDX experts and that a mother passed her MDX knowledge to her daughter. <span style="mso-spacerun: yes;"> </span>Who could have thought that MDX can promote family bonding? I could use stories like this to lift my spirit after finishing another grueling product release cycle at Microsoft.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Without further delay, let’s jump into the MDX Aggregate function which is the focus of this post. Many users think of Aggregate as a smart function that dynamically chooses an aggregation type based on the current measure. But this way of thinking only works when the current measure is a physical measure that has an additive aggregation type like Sum, Min, Max, or Count. What should MDX formula engine do when the current measure is a calculated measure which doesn’t have a default aggregation type? Often times the formula engine simply gives up and returns an error, as seen in <a href="http://www.bidn.com/blogs/DustinRyan/bidn-blog/1936/mdx-aggregate-functions-can-not-be-used-on-calculated-members-in-the-measures-dimension"><span style="color: blue;">this blog</span></a></span><span style="font-family: Calibri;">. Even when the formula engine is able to pick a calculation strategy, it often has limitations that may surprise you when you move beyond basic scenarios. In this blog post I’ll describe three execution plans the formula engine uses to evaluate the Aggregate function and the decision logic employed to pick the winning strategy. The information provided here is valid as of SQL Server 2008R2.<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Here are the three possible execution plans for calculating the value <i style="mso-bidi-font-style: normal;">V</i> of<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Aggregate(«Set»[, «Numeric Expression»]) <o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">in the context of the current cell <em>C</em><span style="font-size: x-small;"><em><sub>0 </sub></em><span style="font-size: small;">whose subspace is <em>S<sub><span style="font-size: x-small;">0</span></sub></em></span></span></span><br />
<br />
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-family: Calibri; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">1.</span><span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";"> </span></span></span></b><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">The basic plan.<o:p></o:p></span></span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Many people think of Aggregate as a generic form of Sum, Min, Max, or Count with a similar execution strategy.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"><span style="font-family: Calibri;">Let <i style="mso-bidi-font-style: normal;">Agg</i> be the aggregation function derived from the current measure in <i style="mso-bidi-font-style: normal;">S<sub><span style="font-size: x-small;">0</span></sub></i><o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"><span style="font-family: Calibri;"><i style="mso-bidi-font-style: normal;">Set V</i> = NULL<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"><span style="font-family: Calibri;">For each tuple <i style="mso-bidi-font-style: normal;">t</i> in «Set»<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.75in;"><span style="font-family: Calibri;">Apply <i style="mso-bidi-font-style: normal;">t</i> to <i style="mso-bidi-font-style: normal;">S<sub><span style="font-size: x-small;">0</span></sub></i> to build a new subspace <i style="mso-bidi-font-style: normal;">S<sub><span style="font-size: x-small;">1</span></sub></i><o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 1in;"><span style="font-family: Calibri;">If «Numeric Expression» is present<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 1.25in;"><span style="font-family: Calibri;">Set <i style="mso-bidi-font-style: normal;">V</i> = <i style="mso-bidi-font-style: normal;">Agg</i>(<i style="mso-bidi-font-style: normal;">V</i>, value of «Numeric Expression» in <i style="mso-bidi-font-style: normal;">S<sub><span style="font-size: x-small;">1</span></sub></i>)<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 1in;"><span style="font-family: Calibri;">Else<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 1.25in;"><span style="font-family: Calibri;">Set <i style="mso-bidi-font-style: normal;">V</i> = <i style="mso-bidi-font-style: normal;">Agg</i>(<i style="mso-bidi-font-style: normal;">V</i>, value property of <i style="mso-bidi-font-style: normal;">S<sub><span style="font-size: x-small;">1</span></sub></i>)<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 0pt;"><span style="font-family: Calibri;">The formula engine chooses this strategy when the current measure in<i style="mso-bidi-font-style: normal;"> S<sub><span style="font-size: x-small;">0</span></sub></i> is a basic physical measure or is an alias to a basic physical measure, as shown below.<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjohcM2MhE4-RMHyK-u-j5bGj7ugN3D3eFUhanTmW27i88VNtakayFC8ZB9NaQEpKvFOz7RroL4eCHSUz7FptO7VJy7Z-edWHtYs_H05lgxtaPY8neNKSCR2xbMdWXs1iboE4Ar5HcaO3I/s1600/basicplan_simplecalcmeasure.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="230" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjohcM2MhE4-RMHyK-u-j5bGj7ugN3D3eFUhanTmW27i88VNtakayFC8ZB9NaQEpKvFOz7RroL4eCHSUz7FptO7VJy7Z-edWHtYs_H05lgxtaPY8neNKSCR2xbMdWXs1iboE4Ar5HcaO3I/s640/basicplan_simplecalcmeasure.png" width="640" /></a></div><div class="MsoNormal" style="margin: 0in 0in 0pt;"><span style="mso-no-proof: yes;"><v:shapetype coordsize="21600,21600" filled="f" id="_x0000_t75" o:preferrelative="t" o:spt="75" path="m@4@5l@4@11@9@11@9@5xe" stroked="f"><span style="font-family: Calibri;"> <v:stroke joinstyle="miter"> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0"> <v:f eqn="sum @0 1 0"> <v:f eqn="sum 0 0 @1"> <v:f eqn="prod @2 1 2"> <v:f eqn="prod @3 21600 pixelWidth"> <v:f eqn="prod @3 21600 pixelHeight"> <v:f eqn="sum @0 0 1"> <v:f eqn="prod @6 1 2"> <v:f eqn="prod @7 21600 pixelWidth"> <v:f eqn="sum @8 21600 0"> <v:f eqn="prod @7 21600 pixelHeight"> <v:f eqn="sum @10 21600 0"> </v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:formulas> <v:path gradientshapeok="t" o:connecttype="rect" o:extrusionok="f"> <o:lock aspectratio="t" v:ext="edit"> </o:lock></v:path></v:stroke></span></v:shapetype></span><o:p></o:p></div><div class="MsoNormal" style="margin: 0in 0in 0pt;"></div><div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.25in; mso-add-space: auto; mso-list: l0 level1 lfo1; text-indent: -0.25in;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-family: Calibri; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">2.</span><span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";"> </span></span></span></b><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">The switching-solve-order plan.<o:p></o:p></span></span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The basic plan stops working when the current measure is a non-trivial calculated measure since the formula engine cannot extract the <i style="mso-bidi-font-style: normal;">Agg</i> function any more. One way to work around the problem is to switch the solving order of the AGGREGATE function and the calculated measure. Mosha alluded to this strategy in his comment to <a href="http://thomasivarssonmalmo.wordpress.com/2007/07/13/proclarity-totals-and-mdx-aggregate/"><span style="color: blue;">Thomas Ivarsson’s post</span></a>.</span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"><br />
<span style="font-family: Calibri;">Let «Measure Expression» be the expression of the current measure in <i style="mso-bidi-font-style: normal;">S<sub><span style="font-size: x-small;">0</span></sub></i><o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"><span style="font-family: Calibri;">Set<i style="mso-bidi-font-style: normal;"> V</i> = Calculate the value of «Measure Expression» in <i style="mso-bidi-font-style: normal;">S<sub><span style="font-size: x-small;">0</span></sub></i></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The thinking behind this strategy is that by evaluating «Measure Expression» first, it will eventually lead to a physical measure that has a good <i style="mso-bidi-font-style: normal;">Agg</i> function. Afterwards, the Aggregate calculation can be evaluated using the basic plan. This strategy essentially moves an otherwise higher-priority Aggregate calculation behind lower priority calculated measures.</span><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">For example, when I slightly change the expression for calculated measure [x] to be more than just a physical measure name, the formula engine would switch the solving orders of [x] and [y] to produce the same result as in the basic plan.<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEKDFvPBGrSyqZsvTRzIwNxryxesrTgiSXsfmZLmo2OCs4TV7v7o5z5XyV9XzZo_oErSYYq4OR47PSkBUqQwH7__oewsAica-piJY1cGyzU4LpwcWzvrHWNgZofCu-SddOvOmKZOpa0Pw/s1600/switchorderplan.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="226" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEKDFvPBGrSyqZsvTRzIwNxryxesrTgiSXsfmZLmo2OCs4TV7v7o5z5XyV9XzZo_oErSYYq4OR47PSkBUqQwH7__oewsAica-piJY1cGyzU4LpwcWzvrHWNgZofCu-SddOvOmKZOpa0Pw/s640/switchorderplan.png" width="640" /></a></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
<span style="font-family: Calibri;">But this strategy falls apart when the calculated measure is more than just a single expression.<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">If you create [x] and [y] in the cube script in the following fashion,</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"><span style="font-family: Calibri;">CREATE MEMBER CURRENTCUBE.Measures.[x] AS NULL;<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"><span style="font-family: Calibri;">Measures.[x] = [Measures].[Internet Sales Amount];<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"><span style="font-family: Calibri;">CREATE MEMBER CURRENTCUBE.[Date].[Calendar Year].[y] AS NULL; <o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"><span style="font-family: Calibri;">[Date].[Calendar Year].[y] =<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.75in;"><span style="font-family: Calibri;">AGGREGATE({[Date].[Calendar Year].&[2007], [Date].[Calendar Year].&[2008]});<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt;"><br />
<span style="font-family: Calibri;">you will get the following surprising query result.<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9W67SDv5Ju4OM0bbE8of-01QhwF-SYgRgcvmRSe6Ynripu26SwHNGKqcbMkSx0B3-PTHUH9y5bfAT6UgObqEprg_xATRNYPD5JLexF6E_OIQri-gbAtFZSgBlMmi7dGrmgcDm9XlyJoM/s1600/switchorder_dontwork.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="144" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9W67SDv5Ju4OM0bbE8of-01QhwF-SYgRgcvmRSe6Ynripu26SwHNGKqcbMkSx0B3-PTHUH9y5bfAT6UgObqEprg_xATRNYPD5JLexF6E_OIQri-gbAtFZSgBlMmi7dGrmgcDm9XlyJoM/s200/switchorder_dontwork.png" width="200" /></a></div><div class="MsoNormal" style="margin: 0in 0in 0pt;"><span style="mso-no-proof: yes;"></span><o:p></o:p></div><div class="MsoNormal" style="margin: 0in 0in 0pt;"></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">This is because the formula engine can only retrieve the original expression of the calculated measure but is unable to take into account scope assignments which also affect the value of the calculated measure. In my opinion, this strategy is more or less a hack as it doesn’t provide a coherent solution under all circumstances. <o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt;"></div><div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.25in; mso-add-space: auto; mso-list: l0 level1 lfo1; text-indent: -0.25in;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-family: Calibri; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">3.</span><span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";"> </span></span></span></b><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">The set-in-the-where-clause plan.</span></span></b></div><div class="MsoListParagraph" style="margin: 0in 0in 10pt 0.25in; mso-add-space: auto; mso-list: l0 level1 lfo1; text-indent: -0.25in;"></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Neither of the above strategies works when the current measure is a physical measure with a non-additive function, such as semi-additive measures or distinct count measures. To make the function return meaningful result, we borrowed a page from another hacky feature of MDX: multi-select through query-scope calculated member using Aggregate function. The formula engine rewrites the incoming multi-select query into an equivalent query by putting the set argument extracted from the Aggregate function into the where clause.<o:p></o:p></span></div><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiBxtqRDl5ORonmB31uhnIF1uH6YXNz7UxJ8Y1jTyreqer6-UVTMLzm5-x2ftbFBD5pohZ2XQctUOiDIO-BLlDID-1d17tt7vT5Rm5YtDojyy8A610ZnRCf03PCJQbaf7w4Vzoy443Xig/s1600/replace_calcmember_setinwhere.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="346" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiBxtqRDl5ORonmB31uhnIF1uH6YXNz7UxJ8Y1jTyreqer6-UVTMLzm5-x2ftbFBD5pohZ2XQctUOiDIO-BLlDID-1d17tt7vT5Rm5YtDojyy8A610ZnRCf03PCJQbaf7w4Vzoy443Xig/s640/replace_calcmember_setinwhere.png" width="640" /></a></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="mso-no-proof: yes;"></span><o:p></o:p></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">As it turned out, the same strategy can be used as a generic solution for evaluating the Aggregate function. In 2008R2, this is used for non-additive physical measures.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"><span style="font-family: Calibri;">Construct a new subspace <i style="mso-bidi-font-style: normal;">S<sub><span style="font-size: x-small;">1</span></sub></i> by adding «Set» as a slice to <i style="mso-bidi-font-style: normal;">S<sub><span style="font-size: x-small;">0</span></sub></i><o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"><span style="font-family: Calibri;">If «Numeric Expression» is present<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.75in;"><span style="font-family: Calibri;">Set <i style="mso-bidi-font-style: normal;">V</i> = Calculate the value of «Numeric Expression» in <i style="mso-bidi-font-style: normal;">S<sub><span style="font-size: x-small;">1</span></sub></i><o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"><span style="font-family: Calibri;">Else<o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.75in;"><span style="font-family: Calibri;">Set <i style="mso-bidi-font-style: normal;">V</i> = Calculate the value property of <i style="mso-bidi-font-style: normal;">S<sub><span style="font-size: x-small;">1</span></sub></i><o:p></o:p></span></div><div class="MsoNormal" style="margin: 0in 0in 0pt 0.5in;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">If you are familiar with DAX, this strategy is similar to the Calculate function in DAX: it transforms the current subspace by applying the set argument as a filter and then evaluates the «Numeric Expression» in the new subspace. </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Conclusion<o:p></o:p></span></span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">As you can see from today’s discussion, current implementation of the Aggregate function in the face of a calculated measure has limitations and inconsistencies. It may cause confusions among users who saw that basic scenarios worked and then ventured into more advanced usages. Therefore we are considering to give users an option to switch to the set-in-the-where-clause plan where currently the switching-solve-order plan is used.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"></div>Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com2tag:blogger.com,1999:blog-8486191632104654344.post-22544401062742896532011-08-17T15:49:00.000-07:002011-08-17T15:49:27.476-07:00Interaction between MDX Subselect and Calculation<span style="font-family: Calibri;">As Mosha </span><span style="color: black; mso-themecolor: text1;"><span style="font-family: Calibri;">Pasumansky</span></span><span style="font-family: Calibri;"><span style="color: black; mso-themecolor: text1;"> </span>has described in his blog <i style="mso-bidi-font-style: normal;"><a href="http://sqlblog.com/blogs/mosha/archive/2008/11/04/as2008-mdx-subselects-and-create-subcube-in-non-visual-mode.aspx"><span style="color: blue;">AS2008MDX: subselects and CREATE SUBCUBE in non-visual mode</span></a></i></span><span style="font-family: Calibri;">, an MDX subselect performs two functions:<o:p></o:p></span><br />
<br />
<ol><li><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Limits each axis set through dimension autoexists.<o:p></o:p></span></div></li>
<li><span style="font-family: Calibri;">Applies visualtotals to cell values if there are no coordinate overwrites.<o:p></o:p></span></li>
</ol><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The second point deserves more elaboration especially when there are MDX calculations involved. In this blog post, I will explain how subselect visualtotals works in MDX formula engine and how the presence of MDX calculations can disable visualtotals by overwriting subselect attributes. Let’s start by looking at a series of questions recently raised by an AS customer. Since the original questions were based on customer’s database, I have adapted them to using AdventureWorks.</span><br />
</div><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-family: Calibri; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">1. </span></span></span></b><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">A customer puzzle<o:p></o:p></span></span></b><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">First run the following MDX query to find out the original values of USA, CA, and WA.</span><br />
</div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVu4c2nIv3fuSzx7-S0q-E_ZFONQ-IvIKrV3jQilHsPXlbAuFTDlG6OvK9QmBaCCMssxFqbgEWjbsDkoePOf_Dz_iFFwMFqo8wOsHPmK3Br6kugg0UbXEjY8S0cMUCl15-4JGJE6asem0/s1600/Figure1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="165" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVu4c2nIv3fuSzx7-S0q-E_ZFONQ-IvIKrV3jQilHsPXlbAuFTDlG6OvK9QmBaCCMssxFqbgEWjbsDkoePOf_Dz_iFFwMFqo8wOsHPmK3Br6kugg0UbXEjY8S0cMUCl15-4JGJE6asem0/s400/Figure1.png" width="400" /></a><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-no-proof: yes;"><v:shapetype coordsize="21600,21600" filled="f" id="_x0000_t75" o:preferrelative="t" o:spt="75" path="m@4@5l@4@11@9@11@9@5xe" stroked="f"> <v:stroke joinstyle="miter"> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0"> <v:f eqn="sum @0 1 0"> <v:f eqn="sum 0 0 @1"> <v:f eqn="prod @2 1 2"> <v:f eqn="prod @3 21600 pixelWidth"> <v:f eqn="prod @3 21600 pixelHeight"> <v:f eqn="sum @0 0 1"> <v:f eqn="prod @6 1 2"> <v:f eqn="prod @7 21600 pixelWidth"> <v:f eqn="sum @8 21600 0"> <v:f eqn="prod @7 21600 pixelHeight"> <v:f eqn="sum @10 21600 0"> </v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:f></v:formulas> <v:path gradientshapeok="t" o:connecttype="rect" o:extrusionok="f"> <o:lock aspectratio="t" v:ext="edit"> </o:lock></v:path></v:stroke></v:shapetype></span></span><br />
<span style="font-family: Calibri;"><span style="mso-no-proof: yes;"><v:shapetype coordsize="21600,21600" filled="f" o:preferrelative="t" o:spt="75" path="m@4@5l@4@11@9@11@9@5xe" stroked="f"><v:stroke joinstyle="miter"><v:path gradientshapeok="t" o:connecttype="rect" o:extrusionok="f"><o:lock aspectratio="t" v:ext="edit"></o:lock></v:path></v:stroke></v:shapetype></span></span><span style="font-family: Calibri;">Since the value of CA is $5,714,257.69, if we query USA while subselecting by CA, the visual totaled value of USA is $5,714,257.69 as well.</span><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkf_TjtTP6ETu0YfuCWv3FJzk1zBV4dC4w12E7oYUfTJxsYu3cY63msu5hjmBLMgpvfEq-d9IeRsXVrewKFI3gVetFvl4B1lriMDB_4JOnk4LzcF54OI8qAl-FxoBxKwzatkUxBCgvDHU/s1600/Figure2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="115" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkf_TjtTP6ETu0YfuCWv3FJzk1zBV4dC4w12E7oYUfTJxsYu3cY63msu5hjmBLMgpvfEq-d9IeRsXVrewKFI3gVetFvl4B1lriMDB_4JOnk4LzcF54OI8qAl-FxoBxKwzatkUxBCgvDHU/s640/Figure2.png" width="640" /></a></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Case 1</span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Now if you insert a seemingly innocuous calculation into the cube script that simply says USA = USA, </span><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm6BsBTY075uZItOZ4-AtDNRVxXLtc9YsSMs9Jw5QgNL0lTtOA_mk4fykchq2K1LMnmquT1qp2y7N3PdkyhDJBN3aKRGE2jDbwBzI75-HrFGkqmoenNs7zqxqtlPe-G63jGuTMrWRdoVc/s1600/Figure3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="44" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm6BsBTY075uZItOZ4-AtDNRVxXLtc9YsSMs9Jw5QgNL0lTtOA_mk4fykchq2K1LMnmquT1qp2y7N3PdkyhDJBN3aKRGE2jDbwBzI75-HrFGkqmoenNs7zqxqtlPe-G63jGuTMrWRdoVc/s640/Figure3.png" width="640" /></a></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">the value of USA suddenly goes back to its original value.</span><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKJnyDt8A2Ik4WgOir9K5odE0JVsP__97mrhgIdrJbg11OHJ2xWuhq-2dgdzi2NmptXj7-asIJGDOAWTnPujflsFg9vSFe0t1DRGHOoQ8XYfShGOC6M8iWjpw4LLsJibqO2FCAJqxBABc/s1600/Figure4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKJnyDt8A2Ik4WgOir9K5odE0JVsP__97mrhgIdrJbg11OHJ2xWuhq-2dgdzi2NmptXj7-asIJGDOAWTnPujflsFg9vSFe0t1DRGHOoQ8XYfShGOC6M8iWjpw4LLsJibqO2FCAJqxBABc/s640/Figure4.png" width="640" /></a></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Case 2<o:p></o:p></span></b></div><span style="font-family: Calibri;">What the user really wanted was to define a calculation that calculates USA as the sum of CA and WA.</span><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHbtP9pBszzbGolwk1YJd4xCGw0P2CkAEot23DIQxPpbfgbTqg3TMpaJWqWoeks2PXAqi4LYA7QKIJugZ53k_12m_LaYDEGGu82W3HeJe2a87F7KUMMlY2tr3kia3txIKDJjIPCwCE66A/s1600/Figure5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="56" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHbtP9pBszzbGolwk1YJd4xCGw0P2CkAEot23DIQxPpbfgbTqg3TMpaJWqWoeks2PXAqi4LYA7QKIJugZ53k_12m_LaYDEGGu82W3HeJe2a87F7KUMMlY2tr3kia3txIKDJjIPCwCE66A/s640/Figure5.png" width="640" /></a></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">But he was not able to get visualtotals when he subselected CA. The value of USA is the sum of the values of CA and WA instead of just the value of CA.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCKLp3CtT364Tj7YcS1P_AlpaabFoDm-QtJynRStlAEKKY0w-43bFXL6RN_uPVG3BSWMv2SwQuEzxGcT91yw6IkIO8xj2PRRrhxTOH06YgLUv5smNbTvkvJU6mBkHofVloJ8D_oesoSJc/s1600/Figure6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="124" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCKLp3CtT364Tj7YcS1P_AlpaabFoDm-QtJynRStlAEKKY0w-43bFXL6RN_uPVG3BSWMv2SwQuEzxGcT91yw6IkIO8xj2PRRrhxTOH06YgLUv5smNbTvkvJU6mBkHofVloJ8D_oesoSJc/s640/Figure6.png" width="640" /></a></div><br />
<b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Case 3<o:p></o:p></span></b></div><span style="font-family: Calibri;">The user further experimented by assigning a constant value to WA. When he put the WA assignment before the USA assignment,</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhonMVM6_FFHAtZPHysj7nuSUpI53GP3q0MznfpWIIYh3NKNB361OMG8-RuE6p7P30acDvmEzIxrSJu8mFS4P2zzZAElVNQ7GVrafkAVK_3ImQUpG0GBsFq8bjhzO6fgKiyUTTGM_e1_mY/s1600/Figure7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="66" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhonMVM6_FFHAtZPHysj7nuSUpI53GP3q0MznfpWIIYh3NKNB361OMG8-RuE6p7P30acDvmEzIxrSJu8mFS4P2zzZAElVNQ7GVrafkAVK_3ImQUpG0GBsFq8bjhzO6fgKiyUTTGM_e1_mY/s640/Figure7.png" width="640" /></a></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">USA value was still the sum of the values of CA and WA.</span><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvuy7Fe0GGo2u2VQOEpCBwx4YqznBFCLlR-AKcAs6EkIEdL0L0LMNZP4TgnO6LKrz5C11ILXoAyRivUySweSFcNNT6tWYXEfrIb_iOOeUCUizGrMhHxH1yeXvAa4OOyH9pmLg6RJmE1EQ/s1600/Figure8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="124" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvuy7Fe0GGo2u2VQOEpCBwx4YqznBFCLlR-AKcAs6EkIEdL0L0LMNZP4TgnO6LKrz5C11ILXoAyRivUySweSFcNNT6tWYXEfrIb_iOOeUCUizGrMhHxH1yeXvAa4OOyH9pmLg6RJmE1EQ/s640/Figure8.png" width="640" /></a></div><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Case 4<o:p></o:p></span></b></div><span style="font-family: Calibri;">When the user moved the WA assignment after the USA assignment,</span><br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu8hztOuOK5jDWb-dOhZYnD8N1iaUo37MP0V1jQmnuM14imSow6ogOYOYw6unJBZ0eQy4N3R5CoQWwj_4nAciQdhTOPw4JdHvPrrRh_dXixuGUTeplv_XN8MuOiIuT18XZBrV7hKzla0U/s1600/Figure9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="68" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgu8hztOuOK5jDWb-dOhZYnD8N1iaUo37MP0V1jQmnuM14imSow6ogOYOYw6unJBZ0eQy4N3R5CoQWwj_4nAciQdhTOPw4JdHvPrrRh_dXixuGUTeplv_XN8MuOiIuT18XZBrV7hKzla0U/s640/Figure9.png" width="640" /></a><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">he suddenly got visualtotals on USA!</span><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsYx5Wmf5Zv43btAPmtbDzs-0S03Qq_01xQMIBWneC-_KQqCCrdnKXT9v1y96jLeWtoegyoh-0Z-fB6KCG82Lv7AANmpmIWfd8WJ-vXTQPczz0uTMcnEUiKbCoIiibFL7o5eeuqpbGe6g/s1600/Figure10.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="122" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsYx5Wmf5Zv43btAPmtbDzs-0S03Qq_01xQMIBWneC-_KQqCCrdnKXT9v1y96jLeWtoegyoh-0Z-fB6KCG82Lv7AANmpmIWfd8WJ-vXTQPczz0uTMcnEUiKbCoIiibFL7o5eeuqpbGe6g/s640/Figure10.png" width="640" /></a></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The above results confused quite a few MDX users.<o:p></o:p></span></div><br />
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-family: Calibri; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">2. </span></span></span></b><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">How does subselect visualtotals work anyway?</span></span></b><br />
<br />
<b style="mso-bidi-font-weight: normal;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">2.1.</span><span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";"> </span></span></span></b><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Subselect filters without calculation</span></b><br />
<br />
<span style="font-family: Calibri;">You can rest assured that there is a consistent logic underneath the above perplexing results. Before we study the interaction between subselect and calculation, let’s first go back to the basics to see how subselect visualtotals is attained when there is no calculation at all.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">I’ll start with a quick review of some fundamentals of the formula engine. Every MDX query is split into one or more single-granularity queries. A single-granularity query is represented by a cube subspace, also known as subcube. The formula engine constructs evaluation nodes from those single-granularity subspaces. For every evaluation node, the formula engine determines which calculations apply to its subspace and generates a list of calculation items, one for each applicable calculation. In the future, you will see that calculation item is also called evaluation node item. But I will stick with calculation item in this post. Every calculation is associated with a subspace at the granularities where the calculation is defined. For example, the left side of the trivial assignment USA = USA defines a subspace with granularity at Country level. The formula engine then constructs a subspace for each calculation item by combining the evaluation node subspace with the calculation subspace. The process of constructing an item subspace is too complex to be covered here, but the resulting subspace is always at or below the granularities of the evaluation node subspace. That’s because a calculation simply doesn’t apply to an evaluation node if the subspace of the former is not strictly at or below the granularities of the subspace of the latter. For example, an assignment at the Country level does not affect a query at the City level. The diagram below illustrates an evaluation node and its calculation items. </span><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUTMYWwigSCPI-aoLiSpDfBUatxM-HzqmK-vgojIYfXG01A1dx0NTMI1JD6sNCfRepa24GnlaVL2GVvMx0iiNQpn5i4BzXy2N3feXqrejtN7ic9CZv4phKqErRUAOccEn1hc1UrclQNgg/s1600/CoverItemSubspaces.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="241" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUTMYWwigSCPI-aoLiSpDfBUatxM-HzqmK-vgojIYfXG01A1dx0NTMI1JD6sNCfRepa24GnlaVL2GVvMx0iiNQpn5i4BzXy2N3feXqrejtN7ic9CZv4phKqErRUAOccEn1hc1UrclQNgg/s400/CoverItemSubspaces.png" width="400" /></a></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">In the simplest case when there is no calculation like calculated member, scope assignment, unary operator, etc., the formula engine creates a single, special calculation item, called DetailData, which fetches data from the storage engine. You can imagine that the subspace associated with any DetailData calculation item is always at the lowest granularities for the measures to be fetched. Any subselect filters are then used to filter out unwanted members from the DetailData subspace. Afterwards, when the formula engine aggregates measure values from the DetailData subspace into the evaluation node subspace, you get visualtotals since data has been filtered at the lowest level. In practice, the formula engine does not construct DetailData subspace at the lowest granularities since the storage engine can do more than just retrieving and filtering data at leaf levels, it can also aggregate physical measure values at higher granularities. So the DetailData subcubes sent to the storage engine, as shown in SQL Profiler’s Query Subcube trace events, are typically at higher granularities but include any subselect filters as subcube slices which will filter data at leaf levels.<o:p></o:p></span></div><br />
<b style="mso-bidi-font-weight: normal;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">2.2.</span><span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";"> </span></span></span></b><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Subselect filters with calculations.<o:p></o:p></span></b><br />
<br />
<span style="font-family: Calibri;">As we just said, when there is no applicable calculation, visualtotals is achieved by applying filters to the DetailData subspace and then aggregating measure values into a higher granularity subspace. The same logic extends naturally to cases when calculations come into the picture. Unlike DetailData items, the subspace of an arbitrary calculation is not necessarily at the lowest granularities any more. When building the subspace of the calculation item for a calculation, the formula engine examines each subselect attribute one by one, applies a subselect filter only if the attribute is at or above the granularities of the subspace. So if a subspace is at quarter level, subselect filters at quarter or year levels will be applied to the subspace but subselect filters at month or day levels are skipped. The diagram below illustrates how a subselect partially filters a subspace.</span><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdNI9xYFQZM5eZMnU9S_KOZZ9gBhtyny7Cm5_UB6GsP9XYjazm8YK_7DRjb6Sm6klomoKHhFuLk-zaOVhUDGpUzbVGO3OZaEVvCKCQSfOxkD8Ej1E8F1VKeKmml6BRvKGayp9NdgE_dwg/s1600/SubselectPartialApply.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="222" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdNI9xYFQZM5eZMnU9S_KOZZ9gBhtyny7Cm5_UB6GsP9XYjazm8YK_7DRjb6Sm6klomoKHhFuLk-zaOVhUDGpUzbVGO3OZaEVvCKCQSfOxkD8Ej1E8F1VKeKmml6BRvKGayp9NdgE_dwg/s400/SubselectPartialApply.png" width="400" /></a></div><br />
<span style="font-family: Calibri;">In practice, every time the formula engine constructs a new subspace, be it for an evaluation node or a calculation item, it always applies the subset of subselect filters which are at or above the granularities of the new subspace.<o:p></o:p></span><br />
<br />
<b style="mso-bidi-font-weight: normal;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">2.3.</span><span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";"> </span></span></span></b><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Attributes overwritten by calculations<o:p></o:p></span></b><br />
<br />
<span style="font-family: Calibri;">An MDX calculation is not only defined by the subspace to which it applies, but also by its MDX expression. When the formula engine evaluates an MDX expression, it often transforms one subspace into another by overwriting some of the attributes. For example, MDX tuple expression ([Retailer Sales Amount], [Date].[Fiscal Year].[FY 2011]) changes one subspace to another by overwriting the [Measures] attribute and the [Fiscal Year] attribute and its related attributes. More complex MDX calculation expressions are parsed into formula trees. Subexpressions within a formula tree like tuple expressions or set expressions overwrite attributes in the original subspace to produce new subspaces.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">While the formula engine navigates from one subspace to another, through evaluation nodes and calculation items, it keeps track of all attributes that have been overwritten by calculation expressions so far. When it is time to apply subselect filters to a newly constructed subspace, the formula engine skips all overwritten attributes. This rule sometimes leads to unintuitive results, like the ones we saw earlier in section 1. In case 1, the dummy calculation USA = USA overwrites attributes in the [Customer Geography] hierarchy, later on the DetailData subspace is no longer filtered by the California slice on the [State-Province] attribute, the final value for USA ends up being the sum of values of all states.<o:p></o:p></span></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The rationale behind this rule is that if a user defines a simple calculated measure like ([Internet Sales Amount], [Fiscal Year].[FY 2009]), they really want to see the sales in 2009 when they add this measure to a report even though the report may have a filter on fiscal years 2010 and 2011. If the formula engine had applied the subselect filter after the calculated measure has changed the subspace to fiscal year 2009, user would have got empty result back since the intersection between {2009} and {2010, 2011} yields empty slice on the [Fiscal Year] attribute.</span><br />
</div><b style="mso-bidi-font-weight: normal;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">2.4.</span><span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";"> </span></span></span></b><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Answers to puzzle questions<o:p></o:p></span></b><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Since calculation USA = CA + WA in case 2 and case 3 overwrites attributes in the [Customer Geography] hierarchy as well, the same rule kicks in to prevent the subselect filter on [State-Province] from being applied, hence no visualtotals for USA. The diagram below illustrates that in cases 1 through 3, overwritten attributes prevents subselect visualtotals.</span><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgE3kqQoCmtNzG4iKomxRQolKRw9lBvID9CTAvKw1ZlGtmLrRcXbdXuZkpsdNJm0qhOZalZzxw6Hv8HWVNWgjncOaSxE3A5oc3dhVXwSfEBjjBX1jeGLb60jB7U1tz6zu0dFE2hQ2ILz9A/s1600/SubselectNotApply.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgE3kqQoCmtNzG4iKomxRQolKRw9lBvID9CTAvKw1ZlGtmLrRcXbdXuZkpsdNJm0qhOZalZzxw6Hv8HWVNWgjncOaSxE3A5oc3dhVXwSfEBjjBX1jeGLb60jB7U1tz6zu0dFE2hQ2ILz9A/s640/SubselectNotApply.png" width="486" /></a></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">But what about case 4 when WA = 1000000 is moved after USA = CA + WA? Why did we get visualtotals in that case? This is actually nothing more than a trick question to test how well you know solving orders in MDX. Now that calculation WA = 1000000 has a higher calculation pass value than calculation USA = CA + WA, the latter calculation is not used at all. The diagram below shows that since calculation does not overwrite any attributes, subselect filters still apply.</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv_iTrrHqv1VFRvMnqTM7zE8h_Q-GVy9svumtj3TJ_1EIDBpHvImxS_U8-Spkl1zdlCTT2arluiaXajiPcuia18JMC_oCDa81R8gPU6cLohwAvPxygvQlyrMFScPTX0HbCbN2AtDc9wH0/s1600/SubselectDoesApply.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="323" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv_iTrrHqv1VFRvMnqTM7zE8h_Q-GVy9svumtj3TJ_1EIDBpHvImxS_U8-Spkl1zdlCTT2arluiaXajiPcuia18JMC_oCDa81R8gPU6cLohwAvPxygvQlyrMFScPTX0HbCbN2AtDc9wH0/s640/SubselectDoesApply.png" width="640" /></a></div></div><b style="mso-bidi-font-weight: normal;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">2.5.</span><span style="font-size-adjust: none; font-stretch: normal; font: 7pt/normal "Times New Roman";"> </span></span></span></b><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Caveats<o:p></o:p></span></b><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Note that the rule discussed in 2.3 only applies to subselect visualtotals. MDX VisualTotals function is not affected by overwritten attributes in the same way. The discrepancy between the two styles of visualtotals is due to historical reasons where VisualTotals function had to maintain backward compatibility with SQL Server 2000 behavior.<o:p></o:p></span></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Also note that the current implementation has complications when an MDX query mixes subselect with set in the where clause. So it’s generally not a good idea to use both features together in the same query.<o:p></o:p></span></div><br />
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-family: Calibri; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">3. </span></span></span></b><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">What if a subselect is arbitrarily shaped?<o:p></o:p></span></span></b><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">So far we have been applying subselect filters one attribute at a time. We have learned that for a given subspace, some subselect filters can be applied if they are at or above granularity and not overwritten, others cannot be applied if they are below granularity or have been overwritten. This is not an issue when each subselect attribute can be applied independently. What if there is a correlation between two subselect attributes? In AS jargon, what if a subselect is arbitrarily shaped but only a subset of the attributes can be applied to a subspace? In this case, the formula engine projects the subselect onto the applicable filter attributes and then restricts the subspace with the projected set. But if a partial projection is caused by some of the filter attributes overwritten by calculations, the formula engine raises an error instead. For example, insert a dummy calculation WA = WA into the cube script that overwrites the [State-Province] attribute. Issue a query <i style="mso-bidi-font-style: normal;">Select USA From (Select {(CA, 2009), (WA, 2008)} From AW)</i> which contains an arbitrary shape subselect and you will get the error <i style="mso-bidi-font-style: normal;">Expression cannot be resolved in the context of an arbitrary shape</i>. That’s because the [Fiscal Year] attribute of the arbitrary shape set applies to the subspace but the [State-Province] attribute of the arbitrary shape set does not apply as it has been overwritten by the dummy calculation.<o:p></o:p></span></div><br />
<b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-family: Calibri; mso-bidi-font-size: 11.0pt; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">4. </span></span></span></b><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Summary<o:p></o:p></span></span></b><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Today we have learned how MDX formula engine implements subselect visualtotals. In general, subselect filters newly constructed subspaces for attributes at or above granularities. The DetailData calculation item can be thought of as working at the leaf levels therefore all subselect filters apply. Other calculation items may work at higher levels hence only a subset of subselect filters are used to restrict their subspaces. Attributes overwritten by calculations are not filtered by subselect.</span><br />
</div>Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com14tag:blogger.com,1999:blog-8486191632104654344.post-48554993357071060942011-06-27T18:32:00.000-07:002011-06-28T23:20:38.099-07:00Under the Covers: MDX IF Statement<span style="font-family: Calibri;">It is a well-known best practice in the MDX community to avoid run-time checks by choosing SCOPE over IIF function, and for the same reason, the IF statement. But what is the actual performance impact when you have no choice but to use IIF function or IF statement? I have described in details the block mode algorithm for IIF function in one of my <a href="http://mdxdax.blogspot.com/2011/01/mdx-iif-execution-plans-and-plan-hints.html"><span style="color: blue;">previous blog posts</span></a></span><span style="font-family: Calibri;">. The other day, <a href="http://prologika.com/CS/blogs/blog/default.aspx"><span style="color: blue;">Teo Lachev</span></a></span><span style="font-family: Calibri;"> asked whether he needed to worry about performance if he used IF statement in his cube script. In particular, Teo wanted to know if there was any performance impact on other calculations which kick in when the condition of IF statement is false. In my post about IIF function, I mentioned that IF statement is internally rewritten as IIF function calls. Today I am going to add a bit more details on how the rewriting is done and what limitations can prevent the rewriting from happening. What is described here applies equally to the CONDITION clause in a CREATE CELL CALCULATION statement since there is no internal difference between the two MDX features. </span><span style="font-family: Calibri;"><o:p></o:p></span> <br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
<b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Rewrite to IIF function calls</span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Let’s consider a simple case where two calculations apply to the same subspace S<sub><span style="font-size: x-small;">0</span></sub>, as shown in Figure 1. The calculation, Calc1, wrapped in IF statement has higher priority over the other calculation, Calc2. For example, Calc1 may be at a higher calculation pass than Calc2. When comparing two scope specifications, MDX calculation engine does not take into account conditions of IF statements although they appear to be part of the scope definitions. Instead, conditions in IF statements are evaluated at run-time. <o:p></o:p></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxFfJFBaEru_5POjNDJBPTlt4NDC21UWSr6Pk7YKXEB-DswDSJU72tHcXUSRDxIOmTndK1WqTJ7zU4bcjKxt1tC8oMoK_wt0vitovDZ_ZwXGm7Q4c8HnxuS28S_NlSyGzLBjor1PyHffw/s1600/Figure1.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="391" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxFfJFBaEru_5POjNDJBPTlt4NDC21UWSr6Pk7YKXEB-DswDSJU72tHcXUSRDxIOmTndK1WqTJ7zU4bcjKxt1tC8oMoK_wt0vitovDZ_ZwXGm7Q4c8HnxuS28S_NlSyGzLBjor1PyHffw/s400/Figure1.gif" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">In case you wonder why Calc1 and Calc2 have their own subspaces S<sub><span style="font-size: x-small;">1</span></sub> and S<sub><span style="font-size: x-small;">2</span></sub> even though the evaluation node already has a subspace S<sub><span style="font-size: x-small;">0</span></sub>, that’s because the scope of a calculation can be at lower granularity than the subspace of an evaluation node. For example, a query may ask for results at the year level, but there is a calculation at month level. In this case, the calculation is needed to answer the query but the subspace for the evaluation node, which is the same as the subspace of the query, and the subspace of the calculation will be at different granularities.<o:p></o:p></span></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Figure 2 shows how the IF statement is translated to IIF function calls which are evaluated at run-time. DisjointTest is an internal function that takes as input a given cell and returns true if the cell is not covered by one of the higher priority calculations. In our example, when S<sub><span style="font-size: x-small;">1</span></sub> and S<sub><span style="font-size: x-small;">2</span></sub> are at the same granularity, DisjointTest degenerates into NOT Condition, which returns true when the condition of IF statement returns false. When S<sub><span style="font-size: x-small;">2</span></sub> has lower granularity than S<sub><span style="font-size: x-small;">1</span></sub>, DisjointTest first finds a cell in S<sub><span style="font-size: x-small;">1</span></sub> that covers the given cell in S<sub><span style="font-size: x-small;">2</span></sub> and then evaluates NOT Condition in the context of the covering cell.<o:p></o:p></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqf3mz06-PSmWHZEYA7iThwZiotgPw3xCTDvDTCaQ_2f3KqhnxITGLOPPXeT_lRbyIqnSNDEEqqbKMpWRDx_4NI0utNULn1HzOHOPe3Vz9iLJoTB3O1nVjSH4y4QVrH2C5PQWCoHd3maU/s1600/Figure2.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="338" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqf3mz06-PSmWHZEYA7iThwZiotgPw3xCTDvDTCaQ_2f3KqhnxITGLOPPXeT_lRbyIqnSNDEEqqbKMpWRDx_4NI0utNULn1HzOHOPe3Vz9iLJoTB3O1nVjSH4y4QVrH2C5PQWCoHd3maU/s400/Figure2.gif" width="400" /></a></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">So unlike IIF(Condition, Calc1, Calc2), where the Condition is evaluated in one subspace, the condition of IF statement is replicated and evaluated in all subspaces of lower priority calculations which apply to the given evaluation node. Consequently, the condition of IF statement will be evaluated in many more cells than the original subspace, especially when the subspaces of lower priority calculations are at lower granularities.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
<b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Exceptions</span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The internal rewriting to IIF does not happen in S<sub><span style="font-size: x-small;">2</span></sub> when Calc2 is a semi-additive measure, a unary operator, or a storage engine query. In those cases, Calc2 is evaluated in a larger subspace not constrained by the opposite condition of the IF statement. This is typically not a problem when Calc2 is to simply fetch data from the storage engine except for really large cubes when fetching the extra data requires a lot of disk IOs. In the other two cases, S<sub><span style="font-size: x-small;">2</span></sub> becomes inexact since now Calc2 is evaluated in more cells than it should. An inexact subspace increases the chance of the MDX calculation engine choosing cell-by-cell mode when it builds the calculation subtree starting from S<sub><span style="font-size: x-small;">2</span></sub>.</span></div>Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com0tag:blogger.com,1999:blog-8486191632104654344.post-31239135300013159432011-05-31T23:07:00.000-07:002011-05-31T23:07:38.641-07:00Performance Considerations for Recursive Calculations in MDX (Part 2)<span style="font-family: Calibri;"><a href="http://mdxdax.blogspot.com/2011/04/performance-considerations-for.html"><span style="color: blue;">Last time</span></a> I discussed MDX engine limitations in dealing with recursive calculations. Today I want to describe two more situations where users may run into bad performance when writing recursive calculations in MDX.<o:p></o:p></span><br />
<br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;"><span style="font-size: large;">Pseudo Infinite Recursion<o:p></o:p></span></span></b></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Last time I recommended users to avoid subspace overlap over the changing attribute of the recursion, in most cases, an attribute in the Date/Time dimension. That’s because MDX calculation engine may choose a cell-by-cell execution plan when it detects sideways recursion. But performance can get a lot worse than simply executing in cell-by-cell mode if MDX calculation engine falsely reports an infinite recursion even though it is actually a sideways recursion. When a calculation applies to two subspaces on the callstack, MDX calculation engine checks for potential infinite recursion. When the two subspaces have overlapping regions, MDX calculation engine checks to see if any cell in one subspace is mapped to itself in the other subspace. This requires MDX calculation engine to keep track of how each MDX expression on the callstack transforms one subspace into another. While there are extensive logic inside MDX formula engine to analyze most common MDX expressions, there are still some MDX expressions which are treated as a black box by the formula engine. Moreover, if one of the subspaces on the callstack is a single-cell subspace, MDX calculation engine switches to lazy execution mode for that expression, and treats the calculation in that subspace as opaque as well. During infinite recursion detection, an opaque calculation on the callstack would force MDX calculation engine to assume the worst and to raise an infinite recursion error even though it is not true.<o:p></o:p></span></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXRckP2TH1j6gh7sC2krYWhFhmeWsbeA9ubQbRjVJQblv7KnFV46TIEk5ha-Q9uDUme3I28JzijV4Nbp-DYJnXvcuXR2o4NEUrAdkMM8NetWaUu0sqcTypLSiuTsblriqw-fArC49jE7g/s1600/PseudoRecursion.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="477" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXRckP2TH1j6gh7sC2krYWhFhmeWsbeA9ubQbRjVJQblv7KnFV46TIEk5ha-Q9uDUme3I28JzijV4Nbp-DYJnXvcuXR2o4NEUrAdkMM8NetWaUu0sqcTypLSiuTsblriqw-fArC49jE7g/s640/PseudoRecursion.gif" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Error handling is one of the most expensive operations in MDX calculation unless the error simply aborts the entire query. This is especially true in block mode. MDX calculation engine is not sure whether the error happens in one of the cells in the subspace or the error applies to the entire subspace. As a result, parent evaluation node which intercepts the error will abandon all intermediate results and start all over by falling back to cell-by-cell mode and recalculating cell values one by one. For the same reason, if an infinite recursion error is raised due to overlapping region and opaque MDX expression anywhere on the callstack, error handling logic at upper level would force a recomputation of cell values one at a time. This is helpful since if the infinite recursion is not real, it won’t happen again as soon as the changing attribute is reduced to a single member. However, the unwinding process happens one level at a time. If the recursion loop is long, recomputations of cell values at all intermediate levels are wasted effort, see Figure 2. <o:p></o:p></span></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6qqki8_YINv9zwSRcoD9gnFP2htldM4f-FLhX8VK5oOm88f6qOgu3YeuS4aUWFhkNteHTg5INVhFkmem_6Hif_dmP2P6tw2hg3OQlv99WzUXjNy6Egk2dC4Sy2bq6OjOxlT0Z7rIZEMI/s1600/ErrorHandling.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="528" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6qqki8_YINv9zwSRcoD9gnFP2htldM4f-FLhX8VK5oOm88f6qOgu3YeuS4aUWFhkNteHTg5INVhFkmem_6Hif_dmP2P6tw2hg3OQlv99WzUXjNy6Egk2dC4Sy2bq6OjOxlT0Z7rIZEMI/s640/ErrorHandling.gif" width="640" /></a></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The false infinite recursion error is repeatedly raised until the beginning of the recursion loop is reached. Only when MDX calculation engine splits the subspace at the beginning of the recursion into individual cells will the false infinite recursion error stops being raised, as by now the beginning subspace would have a single member on the changing attribute and the ending subspace would have a different member on that attribute. To make matters worse, MDX calculation engine has a preference for block mode. Even though a parent level is forced into cell-by-cell mode to avoid false infinite recursion, a child level may still make the same mistake if somehow the subspace is enlarged by some calculation to include more members on the changing attribute. If you see a steady increase of performance counter <em>MDX\Total Recomputes</em> along with the creation of large numbers of evaluation nodes of various kinds, your query may have entered such a vicious cycle.<o:p></o:p></span></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb8cFL3NMWs7qqx8WIH4le7haoFMeWHLRtcfqLOY1H8ygeCQRqQ6juCqgMhVYG9v5b-pju68X65o5Reu5XXWkRXcnXZWeez13M7jjI_8Foygu52WcYcQ8wz4DzFCgYGqAsSWaFmH0tsAo/s1600/Recomputes.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="15" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb8cFL3NMWs7qqx8WIH4le7haoFMeWHLRtcfqLOY1H8ygeCQRqQ6juCqgMhVYG9v5b-pju68X65o5Reu5XXWkRXcnXZWeez13M7jjI_8Foygu52WcYcQ8wz4DzFCgYGqAsSWaFmH0tsAo/s400/Recomputes.jpg" width="400" /></a></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;"><span style="font-size: large;">Impact on Calculation Caches<o:p></o:p></span></span></b></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Aggressively caching intermediate results is one of the key reasons for MDX execution engine to deliver great query performance. MDX execution engine maintains a complex system of various types of caches for different purposes. When a MDX query requires heavy calculation, caches for evaluation nodes tend to play a decisive role in good query performance. An evaluation node is a subspace along with query plans built for all applicable calculations plus, optionally, data caches holding the calculation results. Unlike cached results of storage engine queries which correspond to leaf nodes in an MDX evaluation tree, formula engine evaluation nodes can be at much higher level or even be the root node of an evaluation tree. Hitting or missing an evaluation node at high level in the cache will make a dramatic difference in performance for calculation intensive queries.<o:p></o:p></span></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">MDX calculation engine keeps separate caches for cell-by-cell evaluation nodes and for bulk-mode evaluation nodes. In this section I am going to discuss the impact of recursive calculation on bulk-mode evaluation node caches.<o:p></o:p></span></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The evaluation node cache mentioned above builds hash tables and indexes to facilitate insertions and lookups of cache entries. The hash function used by the hash table calculates hash values based on the group-by attributes of a subspace, plus some other information which is unimportant for the sake of this discussion. The hash table uses linked lists to implement separate chaining for collision resolution. Since every evaluation node ever created is inserted into the cache, the cache becomes crowded very fast. When a linked list becomes too long, evaluation nodes are evicted from the cache, as reflected by the performance counter <em>MDX\Number of evictions of evaluation nodes</em>.<o:p></o:p></span></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Recursion can easily generate a large number of evaluation nodes. Starting from the original query subspace, the evaluation tree can grow quite big as recursion grows deeper and deeper. This in turn puts heavy pressure on evaluation node caches. To exacerbate the situation, the hash function mentioned previously skips group by attributes in parent child dimensions, as a result, subspaces with a lot of parent child dimensions have a much higher chance of hash collision. On the other hand, recursive calculations tend to show up in financial cubes which usually contain a lot of parent child dimensions. So recursion in a cube with a lot of parent child dimensions has a high chance of eviction of cached evaluation nodes and a low chance of hitting a previously built evaluation node.<o:p></o:p></span></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipH-kVMunZx7jQ6Ht1kB5iejfRtExNETbYtneulHI_L3xVmvpJWljYOxePP-hR0FwnXpTqod-iSNY3-12Vqt4_BsnHOygXAxUr5WM1QhdYS_9rjgTSJhX7F7BnNCnzeq8OEqRjGlkaOZc/s1600/LargeEvaluationTree.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipH-kVMunZx7jQ6Ht1kB5iejfRtExNETbYtneulHI_L3xVmvpJWljYOxePP-hR0FwnXpTqod-iSNY3-12Vqt4_BsnHOygXAxUr5WM1QhdYS_9rjgTSJhX7F7BnNCnzeq8OEqRjGlkaOZc/s640/LargeEvaluationTree.gif" width="392" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKH_4kfF4RzB94dPiCH-DK-RghdaJHfwXMAI0sMpqwYysUijJtmqQm62WBzk0OfudUWxgFvn9dvJD1dJ6nniauCNcLiCnLRi1Mpw2kpxq_5jVkhTx72mGkH1SPiJGTyEU0N-3xTyfI9Ns/s1600/HashCollision.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKH_4kfF4RzB94dPiCH-DK-RghdaJHfwXMAI0sMpqwYysUijJtmqQm62WBzk0OfudUWxgFvn9dvJD1dJ6nniauCNcLiCnLRi1Mpw2kpxq_5jVkhTx72mGkH1SPiJGTyEU0N-3xTyfI9Ns/s640/HashCollision.gif" width="640" /></a></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">You can increase the maximum length of all linked lists by increasing the values of private server configuration properties <em>CalculationLRUMinSize</em> and <em>CalculationLRUMaxSize</em> as the eviction threshold is dynamically calculated but always falls in the interval [<em>CalculationLRUMinSize</em>, <em>CalculationLRUMaxSize</em>]. Increasing the size of the linked lists only allows more evaluation nodes to stay in the cache. You also have to increase the value of private server configuration property <em>CalculationCacheRegistryMaxIterations</em> so that those entries are actually examined during cache lookup.<o:p></o:p></span></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;"><span style="font-size: large;">Summary<o:p></o:p></span></span></b></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">In this blog post, we explored two more scenarios in which the presence of recursive MDX calculations can negatively impact query performance. MDX calculation engine may raise false infinite recursion errors when the changing attribute has more than one member in the subspace and when there are a mix of block mode evaluation nodes and cell-by-cell mode evaluation nodes along the recursion path. Although not a definitive diagnosis, you can watch the performance counter <em>Total recomputes</em> to get an indication that unwarranted errors are causing the query slowdown. As recommended in my previous post, keeping a single member on the changing attribute will prevent this issue.<o:p></o:p></span></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">We often find recursive calculations in financial cubes, which also tend to have many parent child dimensions. The combination of the two is cache unfriendly for bulk mode evaluation nodes. Here is one way to help you identify this problem. Assume there is a recursive calculation based on the [Month] attribute. First issue a query to calculate the value in January. After the query finishes, issue a query to calculate the value in February. After that, issue a query to calculate the value in March, so on so forth. If each query comes back fast in this fashion of successive calculations but a query to calculate the value in December is slow when starting in cold cache mode, this is an indication that your recursive calculation can benefit from hitting previously cached results but the large number of evaluation nodes generated by a deep recursion is evicting good cached results. Sometimes increasing the maximum size of hash collision chain of the evaluation node cache may help.<o:p></o:p></span></div><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Most of these problems arise because block mode evaluation can be improved in terms of infinite recursion detection and sideways recursion handling. While that may happen in a future release of Analysis Services, a potential workaround is to force a pure cell-by-cell mode for all calculations. SQL Server 2000 performed calculations in cell-by-cell mode only. Many cubes designed back in SQL Server 2000 days worked well enough in that mode with acceptable and predictable query performance. If none of my other recommendations work for you and you suspect that pure cell-by-cell mode may be what you need, you can contact Microsoft Customer Support and Services to explore such a possibility.</span></div><br />
<img height="3" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb8cFL3NMWs7qqx8WIH4le7haoFMeWHLRtcfqLOY1H8ygeCQRqQ6juCqgMhVYG9v5b-pju68X65o5Reu5XXWkRXcnXZWeez13M7jjI_8Foygu52WcYcQ8wz4DzFCgYGqAsSWaFmH0tsAo/s320/Recomputes.jpg" style="filter: alpha(opacity=30); left: 547px; opacity: 0.3; position: absolute; top: 1866px;" width="96" />Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com0tag:blogger.com,1999:blog-8486191632104654344.post-23269489465858331202011-04-27T17:16:00.000-07:002011-04-28T00:01:02.467-07:00Performance Considerations for Recursive Calculations in MDXThe other day, while investigating a customer performance problem, <span style="color: blue;">Chris Webb</span> came up with a sequence of very simple and targeted MDX queries against SQL Server 2008 Adventure Works database that clearly illustrate some of the pitfalls people may encounter when they write recursive MDX formulas. Today we explore how MDX formula engine generates execution plans for those queries and discuss some engine limitations in this area that may have big impact on query performance.<br />
<br />
<strong>Chris Webb’s Queries</strong><br />
<br />
Chris defined a test measure, [rtest], that recursively counts the number of days from the current date back to 07/01/2001. His first query calculates [rtest] against all customers with a slice on date 07/31/2001. The query finished in about one second to return 118,484 cells.<br />
<br />
<em>Query #1</em><br />
<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">WITH MEMBER MEASURES.rtest AS</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> IIF (</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> [Date].[Date].CURRENTMEMBER IS [Date].[Date].&[20010701]</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> , 1</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> , 1 + (MEASURES.rtest, [Date].[Date].CURRENTMEMBER.PREVMEMBER)</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> )</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">SELECT</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> MEASURES.rtest ON 0,</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> [Customer].[Customer].[Customer].MEMBERS ON 1</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">FROM [Adventure Works]</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">WHERE ([Date].[Calendar].[Date].&[20010731])</span><br />
<br />
Next Chris trimmed down the number of customers to be slightly less than 50% of all customers and ran the query again. The query finished a little bit faster than the first one as expected.<br />
<br />
<em>Query #2</em><br />
<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">WITH MEMBER MEASURES.rtest AS</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> IIF (</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> [Date].[Date].CURRENTMEMBER IS [Date].[Date].&[20010701]</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> , 1</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> , 1 + (MEASURES.rtest, [Date].[Date].CURRENTMEMBER.PREVMEMBER)</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> )</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">SELECT</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> MEASURES.rtest ON 0,</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> HEAD ([Customer].[Customer].[Customer].MEMBERS, 9241) ON 1</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">FROM [Adventure Works]</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">WHERE ([Date].[Calendar].[Date].&[20010731])</span><br />
<br />
But adding one more customer to the second query suddenly increased query execution time to 20 seconds. The obvious question is what is so significant about querying 50% or more of total customers.<br />
<br />
<em>Query #3</em><br />
<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">WITH MEMBER MEASURES.rtest AS</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> IIF (</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> [Date].[Date].CURRENTMEMBER IS [Date].[Date].&[20010701]</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> , 1</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> , 1 + (MEASURES.rtest, [Date].[Date].CURRENTMEMBER.PREVMEMBER)</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> )</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">SELECT</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> MEASURES.rtest ON 0,</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> HEAD ([Customer].[Customer].[Customer].MEMBERS, 9242) ON 1</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">FROM [Adventure Works]</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">WHERE ([Date].[Calendar].[Date].&[20010731])</span><br />
<br />
Chris then tried to remedy the situation by cleverly adding a helper measure, [rtest2], that pre-calculates [rtest] in the range of desired dates in the hope that calculating values of later dates can hit caches of values of earlier dates. I omitted several intermediate queries that led Chris to this idea. When he tried out his idea against the problem query, execution time was cut down to about 12 seconds, an improvement from 20 seconds.<br />
<br />
<em>Query #4</em><br />
<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">WITH MEMBER MEASURES.rtest AS</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> IIF (</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> [Date].[Date].CURRENTMEMBER IS [Date].[Date].&[20010701]</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> , 1</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> , 1 + (MEASURES.rtest, [Date].[Date].CURRENTMEMBER.PREVMEMBER)</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> )</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">MEMBER MEASURES.rtest2 AS</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> IIF (</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> ISEMPTY(</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> SUM(</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> [Date].[Date].&[20010701] : [Date].[Date].CURRENTMEMBER,</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> MEASURES.rtest</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> )</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> )</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> , null</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> , MEASURES.rtest</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> )</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">SELECT</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> MEASURES.rtest2 ON 0,</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> HEAD ([Customer].[Customer].[Customer].MEMBERS, 9242) ON 1</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">FROM [Adventure Works]</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">WHERE ([Date].[Calendar].[Date].&[20010731])</span><br />
<br />
But the same trick didn’t help the original query, which now takes about 38 seconds to finish.<br />
<br />
<em>Query #5</em><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">WITH MEMBER MEASURES.rtest AS</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> IIF (</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> [Date].[Date].CURRENTMEMBER IS [Date].[Date].&[20010701]</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> , 1</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> , 1 + (MEASURES.rtest, [Date].[Date].CURRENTMEMBER.PREVMEMBER)</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> )</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">MEMBER MEASURES.rtest2 AS</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> IIF (</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> ISEMPTY(</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> SUM(</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> [Date].[Date].&[20010701] : [Date].[Date].CURRENTMEMBER,</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> MEASURES.rtest</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> )</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> )</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> , null</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> , MEASURES.rtest</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> )</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">SELECT</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> MEASURES.rtest2 ON 0,</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> [Customer].[Customer].[Customer].MEMBERS ON 1</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">FROM [Adventure Works]</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;">WHERE ([Date].[Calendar].[Date].&[20010731])</span><br />
<br />
<strong>Block Mode vs. Cell-by-Cell Mode</strong><br />
<br />
As it turned out, queries #1 and #2 run fast because they execute in block mode. On the other hand, queries #3, #4, and #5 all execute in cell-by-cell mode. But how do I know that? Well, I admit that Analysis Services product team owes the MDX community good diagnostic features, such as MDX query plans, to easily identify such problems. Before such features become available, we have to make do with what we have today, namely PerfMon counters and SQL Profiler trace events. In this case, PerfMon counters can be very revealing. If you start PerfMon and add the counter <u>MSAS 2008:MDX/Total flat cache inserts</u>, rerun queries #2 and #3 with cache cleared, you will see that the counter stays at 0 during query #2 but jumps to 286,502 at the end of query #3. Flat cache is one of the many data caches maintained by MDX formula engine and is used to store single-cell calculation results. The large number of inserts into this cache during query #3 indicates that the query runs in cell-by-cell mode. I'd like to add that cell-by-cell mode can be reflected in other PerfMon counters under a different circumstance. Just because <u>Total flat cache inserts</u> is zero, does not necessarily mean query is in block mode.<br />
<br />
<strong>Sideways Recursion and Inexact Subspace</strong><br />
<br />
Now we know adding one more customer to query #2 tips MDX formula engine over the edge into cell-by-cell mode, but what is so special about the threshold of 50% of members in an attribute set? When MDX formula engine constructs a query subspace, it does not always construct the exact subspace as specified by the MDXMDX formula engine has an easy way to indicate that all customers are included in the subspace. Later operations like determining overlapping regions between two subspaces or detecting whether a cell belongs to a subspace become fast and efficient. But the real benefit of this expansion is to fetch more fact data into detail data cache, so that following queries have a much higher chance of hitting a cache entry. An obvious downside of this expansion is the possibility of fetching too much data. If there are four years of data in the cube and a query selects two years, AS engine ends up retrieving all four years of data. A much more serious problem with this expansion is when there are calculations applicable to the subspace. A single extra member may introduce an unwanted calculation that kills performance. The 50% threshold is arbitrary and is controlled by private server configuration flag <em>QueryOptimizerRatio</em>. Now change the ratio from -1 to 0.7 and rerun query #3, the query finishes instantly. You should know that Microsoft does not support customers who temper with private server configuration settings without authorization from Microsoft Customer Service and Support.<br />
<br />
So MDX formula engine expanded the subspace for query #3 to include all customers, the expanded subspace ended up being the same as the one in query #1, but why was query #3 so much slower than query #1? In addition to expanding the subspace in query #3, MDX formula engine also marks the query subspace as inexact for the obvious reason that the subspace contains more customers than requested. Inexact subspaces have several repercussions on building query plans. Loosely speaking, whenever MDX formula engine runs into a potentially expensive operation and when one of the parent subspaces is inexact, it is likely to fall back to cell-by-cell plan as the expensive operation may be unnecessarily introduced by the extra members added.<br />
<br />
The next concept to explain is sideways recursion. A recursion happens when the same calculation shows up twice on the stack of current calculations. When the two subspaces to which the calculation is applied have the same granularity and there is no slice change from a regular member to a calculated member or vice visa, the recursion is called sideways recursion. So if one subspace is at All level on an attribute, but the other subspace is at leaf level, the recursion is not a sideways recursion. <br />
<br />
When MDX formula engine detects a sideways recursion in the context of an inexact subspace, it chooses a cell-by-cell execution plan. There are a couple of reasons for making such a choice. In addition to query execution, MDX formula engine is also responsible for detecting infinite recursions. Detecting infinite recursion in block mode is more complicated than in cell-by-cell mode. Even when a calculation shows up twice on the stack of current calculations and the two subspaces to which the calculation is applied have overlapping regions, it does not necessarily entail an infinite recursion. There have been cases where it takes a long time to detect an infinite recursion in block mode and it turns out that time is wasted as the subspace is enlarged through expansion. So currently MDX formula engine resorts to cell-by-cell mode when it encounters sideways recursion and when one of the parent subspaces is inexact. If you want to keep all subspaces exact throughout the execution process to overcome this constraint, you can change another private server configuration property, <em>SpaceDecomposition</em>, from default value of 8 to 9. You can try the new value and rerun query #3 again to see instant result. Why isn’t this default setting? Wouldn’t precise subspaces be a good thing all the time? The Analysis Services product team tried to make the switch during SQL 2008 development but found that precise subspaces hurt performance much more often than helping. Precise subspaces tend to carry a lot of large slices and often arbitrary-shaped slices. Arbitrary-shaped slices are a well-known reason of MDX query performance degradation. More importantly, precise subspaces make it hard to hit caches. Extensive caching of intermediate results is one of the secret recipes of good MDX query and calculation performance.<br />
<br />
<strong>Recursion and Subspaces Overlapping on Shifted Attributes</strong><br />
<br />
Although sound promising in concept, queries #4 and #5 do not perform as well as queries #1 and #2 since they also run in cell-by-cell mode. But the subspace for query #5 is precise, why does it still enter cell-by-cell mode? The execution plan for query #5 enters cell-by-cell mode for a different reason.<br />
<br />
Chris introduced the following helper expression<br />
<br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> SUM(</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> [Date].[Date].&[20010701] : [Date].[Date].CURRENTMEMBER</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> ,MEASURES.rtest</span><br />
<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> )</span><br />
<br />
in the hope that MDX calculation engine will calculate [rtest] on 07/01/2001 first, and then each following day will hit the cached result of the previous day. But MDX formula engine always tries to execute in block mode first. So when constructing the subspace for the evaluation of the scalar argument of SUM, the engine adds all dates from the set argument to the subspace. The diagram below shows the important subspaces constructed when executing query #5.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn7QBqTWLZ_PV0dUQn6jHuPH7GUKxN4IZJxjtD8fSt6KwbyKqS2BRKLJYbgOwiFNKXp4HE1FMAeC8_AAsv3es6PpOF8V3K_2tvWTc3dQzGDXI86PDxahGmYB7nySMw3RO9OtCEQTov6Gw/s1600/Query5.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn7QBqTWLZ_PV0dUQn6jHuPH7GUKxN4IZJxjtD8fSt6KwbyKqS2BRKLJYbgOwiFNKXp4HE1FMAeC8_AAsv3es6PpOF8V3K_2tvWTc3dQzGDXI86PDxahGmYB7nySMw3RO9OtCEQTov6Gw/s640/Query5.jpg" width="640" /></a></div><br />
<div> </div>The steps below illustrate the import stages during query #5 evaluation.<br />
<br />
<span style="font-family: Times, "Times New Roman", serif;">Construct subspace 1 from MDX query.</span><br />
<span style="font-family: Times, "Times New Roman", serif;">Build query plan for calculation rtest2 in subspace 1.</span><br />
<span style="font-family: Times, "Times New Roman", serif;"> Build query plan for sub-expression Sum(07/01/2001 : 07/31/2001, rtest)</span><br />
<span style="font-family: Times, "Times New Roman", serif;"> Construct subspace 2 by adding MDX set 07/01/2001 : 07/31/2001 to subspace 1.</span><br />
<span style="font-family: Times, "Times New Roman", serif;"> Build query plan for calculation rtest in subspace 2.</span><br />
<span style="font-family: Times, "Times New Roman", serif;"> Build query plan for sub-expression (rtest, Date.PrevMember).</span><br />
<span style="font-family: Times, "Times New Roman", serif;"> Construct subspace 3 by shifting all dates in subspace 2 to the previous date.</span><br />
<span style="font-family: Times, "Times New Roman", serif;"> Build query plan for calculation rtest in subspace 3.</span><br />
<span style="font-family: Times, "Times New Roman", serif;"> Detect recursion and overlapping dates. Choose cell-by-cell plan.</span><br />
<br />
When MDX formula engine detects recursion and the two subspaces have overlapping regions, it is potentially an infinite recursion. But the overlapping dates have been shifted, so whether or not there is infinite recursion depends on the MDX operation that performed the shifting. It is obvious in this case there is no infinite recursion. But MDX formula engine has to handle the general case when there are a series of shifting operations between the two subspaces. To play it safe, the engine chooses cell-by-cell execution plan again.<br />
<br />
Why is choosing cell-by-cell mode bad for performance in this case? Doesn’t the recursive formula force the engine to evaluate [rtest] one day at a time anyway? That’s true. But there are also 118,484 customers in the subspace. Right now cell-by-cell is a global decision. While going cell-by-cell over days is not a bad thing in this case, going over customers one by one is. Ideally, we want the formula engine to go block on [Customer] attribute, but cell-by-cell on [Date] attribute.<br />
<br />
Another downside of choosing cell-by-cell mode in subspace 3 is that the decision will propagate back to all parent calculations as well. MDX formula engine cannot take advantage of sparsity of underlying data when calculation is in cell-by-cell mode. Since building execution plan for [rtest] in subspace 3 is a part of building the overall execution plan for [rtest2] in subspace 1, choosing cell-by-cell plan in subspace 3 ends up forcing a bad plan for [rtest2] in subspace 1 as well.<br />
<br />
We don’t have this problem in queries #1 and #2 since there is only a single date in the subspace. When constructing a new subspace, [Date].PrevMember shifts the current date to the previous date. The newly constructed subspace has a different date from all previously constructed subspaces, therefore, there is no risk of infinite recursion. As a result, the execution plan stays in block mode.<br />
<br />
<strong>Deep Recursion and CLR Assembly</strong><br />
<br />
The next topic is unrelated to Chris Webb’s queries but still important for recursions in MDX. Each additional recursive step consumes more space on the stack. A very deep recursion will eventually use up all space on the stack. When that happens, MDX formula engine creates a fiber and switches execution on to the new fiber. But it is not always safe to call managed code from within a fiber since you may get stack overrun problem. In SQL Server 2008 R2, MDX formula engine raises an error when this happens. But the error does not abort the current query to return to user immediately. Most errors cause MDX formula engine to switch to cell-by-cell mode in case some cells contain errors but others don’t. So instead of seeing a query fail quickly, you may end up waiting a long time for it to fail eventually. Note that VBA library is registered as a CLR assembly hosted by Analysis Services, so calling VBA functions in MDX recursion may trigger the fiber exception and cause performance problems. Also note that some <a href="http://cwebbbi.wordpress.com/2007/03/03/vba-functions-in-mdx/"><span style="color: blue;">VBA functions</span></a> have been implemented directly in Analysis Services, therefore are safe to use inside recursion. Setting private server configuration flag <em>AllowCLRStoredProcedureCallsInFiberMode</em> to 1 would prevent the exception from being raised.<br />
<br />
<strong>Conclusions</strong><br />
<br />
So far, we have discussed three important performance limitations imposed by MDX formula engine when it encounters recursions. We have learned that to achieve better performance when writing recursive MDX formulas, you should:<br />
<br />
<ol><li>Don’t write recursive formulas unless really needed. Non-recursive MDX formulas are not subject to the limitations discussed in this post.</li>
<li>Keep the subspaces precise. Try to stay with queries that produce nice, rectangular-shaped query spaces which don’t trigger the 50% rule. Playing with <em>SpaceDecomposition</em> is an option but you need approval from Microsoft Customer Service and Support to use it in production environment. Note that always enforcing precise subspaces is likely to have an overall negative impact on query performance. </li>
<li>Avoid subspace overlap over shifted attributes. Most recursions happen along the time line. Keeping a single date in the subspace is one way to guarantee that subspaces don’t overlap.</li>
<li>Avoid calling into CLR assembly when recursion is very deep.</li>
</ol>As always, performance advices apply to particular versions of a product. The recommendations given in this post apply to all currently supported versions of Analysis Services with the latest one being 2008 R2. The Analysis Services product team will continue to evolve the product and some of the limitations are likely to be lifted in future releases. When you test your recursive calculation, you should start at the beginning and gradually increase recursion <span style="background-color: white;">depth. Observe whether query time increases at worst linearly as recursion depth increases. Make sure you test the case when the recursion is the deepest as needed by the user.</span>Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com8tag:blogger.com,1999:blog-8486191632104654344.post-31177352623967468232011-03-21T23:59:00.000-07:002011-03-22T10:46:07.600-07:00The Logic behind the Magic of DAX Cross Table Filtering<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Automatic cross filtering between columns of the same table or related tables is a very powerful feature of DAX. It allows a measure to evaluate to different values for different cells in a pivot table even though the DAX expression for the measure does not change. Filter context is the underlying mechanism that enables this magic behavior. But it is also a very tricky concept that even befuddles some DAX experts. <a href="http://sqlblog.com/blogs/marco_russo">Marco Russo</a> and <a href="http://sqlblog.com/blogs/alberto_ferrari">Alberto Ferrari</a></span><span style="font-family: Calibri;"> have introduced DAX filter context in Chapter 6 of their book <i style="mso-bidi-font-style: normal;">Microsoft PowerPivot for Excel 2010</i>. Marco has also blogged about <a href="http://sqlblog.com/blogs/marco_russo/archive/2010/01/03/how-calculate-works-in-dax.aspx">how Calculate function works</a>. Recently I have run into many questions from advanced DAX users which tell me that people are still confused about how filter context works exactly. And this will be the subject of today’s post. </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">This post assumes that you already have basic knowledge about measures, row context, filter context, and DAX functions Calculate, Values, All, etc.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">A level 200 pop quiz on DAX</span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">If you think you already know how filter context works, let me ask you a couple of level 200 questions on DAX to see if you can explain the nuances of some DAX expressions. If you don’t feel like being challenged now, it is still beneficial to read the questions so you have some examples to better understand the following sections. The questions are based on the data model inside the publicly available sample PowerPivot workbook <i style="mso-bidi-font-style: normal;"><a href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=1ae63bfb-c303-44e3-ae44-7413d499495d">Contoso Samples DAX Formulas.xlsx</a></i>. You can download the sample workbook to try out the formulas yourself if you want to, but it is not required to answer the questions.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><b style="mso-bidi-font-weight: normal;">Question #1</b>.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">People have heard that fact tables are automatically filtered by slices on dimension tables, but not the other way around, or in more general terms, if there is a relationship from table A to table B, A is automatically filtered by any slices on columns of B but B is not automatically filtered by any slices on columns of A. So if you select</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">DimProductSubcategory[ProductSubcategoryName] = “Air Conditioners” </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">on a pivot table slicer, measure</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">CountRows(DimProduct)</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">returns 62 as DimProduct is limited to air conditioners. On the other hand, if you select</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">DimProduct[ProductLabel] = “0101001”,</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">measure</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">CountRows(DimProductSubcategory)</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">returns 44 instead of just 1 although only a single product is selected. To filter DimProductSubcategory by the selected product label, you can define a measure as</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(CountRows(DimProductSubcategory), DimProduct)</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">which returns 1. So it seems like when you explicitly add DimProduct as a setfilter argument of Calculate, DimProductSubcategory will be filtered by DimProduct. But if I define a measure as</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(CountRows(DimProductSubcategory), Values(DimProduct[ProductLabel])) <span style="mso-spacerun: yes;"> </span></span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">to explicitly add the column that I know having a slice from the pivot table to the Calculate function , the measure formula returns 44 again. So what makes setfilter expression DimProduct work but Values(DimProduct[ProductLabel]) not work even though the filter only comes from [ProductLabel] column? If you think you have to add foreign key DimProduct[ProductSubcategoryKey] to the filter context in order for DimProductSubcategory to be filtered by DimProduct, you can try</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(CountRows(DimProductSubcategory), Values(DimProduct[ProductSubcategoryKey]))</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">but it still returns 44. If you have enough patience, you can use Values function to explicitly add all 33 columns in DimProduct one by one as setfilter arguments to Calculate function and you still will get 44 back. So what is the difference between table expression DimProduct and the enumeration of all 33 columns in that table?</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><b style="mso-bidi-font-weight: normal;">Question #2</b>.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">There are 2556 records in DimDate table, therefore if you add a measure with expression</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">CountRows(DimDate)</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">to a pivot table without any filters, the measure value would be 2556. Now if you add a second measure with expression</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(CountRows(DimDate), FactSales)</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">to the same pivot table, the measure value would be 1096 since DimDate table is filtered by FactSales table and only dates with sales records are included. But if you add a third measure with expression</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(CountRows(DimDate), All(FactSales))</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">to the pivot table, the measure value becomes 2556 again. Since this pivot table has no filters anywhere, shouldn’t FactSales and All(FactSales) return the same table? Now add a fourth measure with expression</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(CountRows(DimDate), Filter(All(FactSales), true))</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">to the pivot table, the measure value becomes 1096 again. All three setfilter arguments return exactly the same table, why would we get back different results?</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">With these questions in mind, let’s examine the logic foundation upon which the magic world of DAX is built. At the end of the post, you will be able to find a logical explanation to all these seemingly inconsistent results.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">The expanded view of a DAX base table</span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The best way to understand DAX cross table filtering is to think of each base table as extended by its related tables. When a relationship is created from table A to table B, the new A, which is really A left outer join B, includes both columns of A and columns of B. So in DAX, a table reference FactSales really refers to </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">FastSales </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">LOJ DimProduct LOJ DimProductSubcategory LOJ DimProductCategory </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">LOJ DimStore LOJ DimGeography LOJ DimDate LOJ DimChannel LOJ DimPromotion,</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">where LOJ means left outer join. This interpretation makes it easy to understand some other DAX syntax. For example, in DAX expression</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Filter(FactSales, Related(DimProduct[ProductLabel]) <span style="mso-spacerun: yes;"> </span>= “0101001”), </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Related(DimProduct[ProductLabel]) <span style="mso-spacerun: yes;"> </span>refers to the value of column DimProduct[ProductLabel] <span style="mso-spacerun: yes;"> </span>in the extended FactSales table. As a second example, DAX expression</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">AllExcept(FactSales, DimProduct[ProductLabel])</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">returns a table with all columns of extended FactSales table except for column DimProduct[ProductLabel].</span></div><div class="separator" style="clear: both; text-align: center;"></div><br />
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYhE44o2z9NTxgMCjUv3rhdwh8vsy8ze2rZtOU_HNpIvt_RRsfOJzAy87qxpnsgenAgRV0GMhnZwbP5gy2kdKLwGg48pK9caQri5WF6F8Y-UKVydVs5-8IIxTs-w1W-Si8Q8Wje6BVvHc/s1600/ExpandedTableView.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" r6="true" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYhE44o2z9NTxgMCjUv3rhdwh8vsy8ze2rZtOU_HNpIvt_RRsfOJzAy87qxpnsgenAgRV0GMhnZwbP5gy2kdKLwGg48pK9caQri5WF6F8Y-UKVydVs5-8IIxTs-w1W-Si8Q8Wje6BVvHc/s1600/ExpandedTableView.gif" /></a></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Build initial filter context</span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">DAX filter context is a stack of tables. At the beginning, the stack is empty. Given a pivot table, a filter context is initially populated by adding slicers and page filters. For each cell in a pivot table, current members of row labels and column labels also add filters to filter context. Other pivot table operations like visual totals add to initial filter context as well but I will keep things simple here. At this point, we have set up an initial filter context in which the measure expression of the current cell is to be evaluated. </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Measure invocation</span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">If SumOfSales is the name of a measure and Sum(Sales[Amount]) is its DAX formula, DAX expression</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">[SumOfSales]</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">is equivalent to</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(Sum(Sales[Amount]))</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-spacerun: yes;"> </span>and DAX expression</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">[SumOfSales](Date[Year] = 2001, Store[Country] = “USA”) </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">is equivalent to</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(Sum(Sales[Amount]), Date[Year] = 2001, Store[Country] = “USA”).</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">So the syntax sugar which makes a measure name look like a function name is just a clever way to add tables to filter context before evaluating the expression associated with the measure. Since invoking a measure implicitly calls Calculate, from now on I’ll just focus on Calculate function as the same rules apply equally to measures.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Add tables to filter context</span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Calculate function performs the following operations:</span></div><div class="MsoListParagraphCxSpFirst" style="margin: 0in 0in 0pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">1.</span><span style="font-family: "Times New Roman";"> </span></span></span><span style="font-family: Calibri;">Create a new filter context by cloning the existing one.</span></div><div class="MsoListParagraphCxSpMiddle" style="margin: 0in 0in 0pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">2.</span><span style="font-family: "Times New Roman";"> </span></span></span><span style="font-family: Calibri;">Move current rows in the row context to the new filter context one by one and apply blocking semantics against all previous tables.</span></div><div class="MsoListParagraphCxSpMiddle" style="margin: 0in 0in 0pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">3.</span><span style="font-family: "Times New Roman";"> Evaluate each setfilter argument in the old filter context and then add</span></span></span><span style="font-family: Calibri;"> setfilter tables to the new filter context one by one and apply blocking semantics against all tables that exist in the new filter context before the first setfilter table is added.</span></div><div class="MsoListParagraphCxSpLast" style="margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">4.</span><span style="font-family: "Times New Roman";"> </span></span></span><span style="font-family: Calibri;">Evaluate the first argument in the newly constructed filter context.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">If a new table is added to filter context and it has blocking semantics against some tables already in the filter context, the affected tables are checked one by one, all common columns with the new table are marked as blocked on the existing table.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Let’s look at an example. Assume the current filter context has two filters: one filter is Date[Year] = 2011, the other filter is Store[Country] = “Canada”. We want to evaluate the following expression in the context</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">AverageX(Distinct(Date[Month]), Calculate(Sum(Sales[Amount]), Store[Country] = “USA”)).</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The first argument of AverageX sets a month in row context. <span style="mso-spacerun: yes;"> </span>When it comes to Calculate, it first removes the month from row context and adds it to filter context, it does not block anything since there is no [Month] column in existing filters. Next Calculate adds Store[Country] = “USA” to filter context which blocks existing filter Store[Country] = “Canada”. When Sum(Sales[Amount]) is evaluated, Sales table is filtered by the current month in 2011 and stores in USA.</span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjId-qQf8vszBCQDGxLqE0IlOuvGF4eCSMOoPtzPAn9kFSNKLAlk3PXVKWlFq-OVfCWqzVV6h1-cCpP1zxao5KNbKeF5BOOi3oy5qepuv2pOakQZLPnk9PNLVNhvmx4tLVJm91RbVmXN5c/s1600/FilterContextOverwrite.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" r6="true" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjId-qQf8vszBCQDGxLqE0IlOuvGF4eCSMOoPtzPAn9kFSNKLAlk3PXVKWlFq-OVfCWqzVV6h1-cCpP1zxao5KNbKeF5BOOi3oy5qepuv2pOakQZLPnk9PNLVNhvmx4tLVJm91RbVmXN5c/s1600/FilterContextOverwrite.gif" /></a></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Targets of filter context</span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">After so much effort populating and modifying a filter context, when will the filters be applied? In DAX, the filters in a filter context apply to following DAX table expressions:</span></div><div class="MsoListParagraphCxSpFirst" style="margin: 0in 0in 0pt 0.5in; mso-list: l1 level1 lfo2; text-indent: -0.25in;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">1.</span><span style="font-family: "Times New Roman";"> </span></span></span><span style="font-family: Calibri;">A table expression that is simply a table reference, such as FactSales.</span></div><div class="MsoListParagraphCxSpMiddle" style="margin: 0in 0in 0pt 0.5in; mso-list: l1 level1 lfo2; text-indent: -0.25in;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">2.</span><span style="font-family: "Times New Roman";"> </span></span></span><span style="font-family: Calibri;">Values(Table[Column]).</span></div><div class="MsoListParagraphCxSpLast" style="margin: 0in 0in 10pt 0.5in; mso-list: l1 level1 lfo2; text-indent: -0.25in;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">3.</span><span style="font-family: "Times New Roman";"> </span></span></span><span style="font-family: Calibri;">Distinct(Table[Column]).</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">In cases of 2 and 3, the Table is filtered by filter context and then distinct values of [Column] are extracted from the filtered table.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">So if your expression is</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(SumX(Filter(FactSales, [SalesQuantity] > 1000), [SalesAmount]), Date[Year] = 2011),</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">the filter context only restricts FactSales and has no effect whatsoever on other parts of the formula. If you image every DAX formula is represented as a tree of parent and child function calls, a filter context is built at the top or in the middle of the tree but takes effect at leaf level table nodes.</span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhE6zpFe_LWWWWHj82BN-JsWIGR8Z1EWP5gE8zAl9VfREsKE29qXfXFZC3D5Prj2We0XfFFaUYW24ABipdlKR_V02Lp2gAGiTnUsRYMWq3lMbmUuA0v69RztS3Mm27Rw-tCrQR9GJzGZsw/s1600/ApplyToLeaf.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" r6="true" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhE6zpFe_LWWWWHj82BN-JsWIGR8Z1EWP5gE8zAl9VfREsKE29qXfXFZC3D5Prj2We0XfFFaUYW24ABipdlKR_V02Lp2gAGiTnUsRYMWq3lMbmUuA0v69RztS3Mm27Rw-tCrQR9GJzGZsw/s1600/ApplyToLeaf.gif" /></a></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Note that DAX function Sum(T[C]) is just a shorthand for SumX(T, [C]), the same is true for other aggregation functions which take a single column reference as argument. Therefore the table in those aggregation functions is filtered by filter context.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Apply filters to a target table</span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Finally we have identified a target table and are ready to apply filters from filter context. For each filter table in the filter context, we check to see if there are any common columns between the target table and the unblocked columns of the filter table. If there is at least one common column, the target table is semi-joined with the filter table, or in SQL-like terms</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">SELECT * </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">FROM TargetTable AS t</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">WHERE EXISTS </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">(</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 1in;"><span style="font-family: Calibri;">SELECT * </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 1in;"><span style="font-family: Calibri;">FROM FilterTable AS f </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 1in;"><span style="font-family: Calibri;">WHERE t.CommonColumns = f.CommonColumns </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">)</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Each filter table is applied to the target table independently, so the target table is filtered by all relevant filters.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">All, AllExcept, AllNoBlankRow</span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">So far I have said that each setfilter argument of Calculate function returns a table which is added to filter context. Well, that is true as long as the setfilter is not one of the All functions. The All functions should really be renamed as BlockColumns when they are used as setfilter arguments. If one of the All functions is used as the top-level function of setfilter, it <b style="mso-bidi-font-weight: normal;">only</b> blocks common columns of earlier tables but does <b style="mso-bidi-font-weight: normal;">not</b> add itself to filter context.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">In all other places, including as a sub-expression of a setfilter but not at the top level, All functions behave like any other DAX table expressions and always return a table. One special feature of All functions is that the Table argument inside All(Table), All(Table[Column]), AllExcept(Table, …), AllNoBlankRow(Table), etc. is not filtered by the current filter context.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Pop quiz answers</span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><b style="mso-bidi-font-weight: normal;">Answer to question #1</b>.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">When the initial filter context contains column DimProduct[ProductLabel], table DimProductSubcategory is not filtered as it does not have that column. </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Now look at the next formula</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(CountRows(DimProductSubcategory), DimProduct).</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The setfilter argument DimProduct is filtered by [ProductLabel], and then table DimProductSubcategory is filtered by table DimProduct since they both share the columns from table DimProductSubcategory and table DimProductCategory.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Move onto the next two formulas</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(CountRows(DimProductSubcategory), Values(DimProduct[ProductLabel]))</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(CountRows(DimProductSubcategory), Values(DimProduct[ProductSubcategoryKey]))</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Both setfilter arguments are a single column table and the column comes from table DimProduct. Since table DimProductSubcategory does not have any column from DimProduct, it is not filtered by filter context. For the same reason, you can add any columns from DimProduct to the filter context and none of them would impact DimProductSubcategory.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><b style="mso-bidi-font-weight: normal;">Answer to question #2</b>.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">In the first formula</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(CountRows(DimDate), FactSales)</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Both table DimDate and table FactSales share columns from DimDate, so DimDate is filtered by FactSales.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">In the second formula</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(CountRows(DimDate), All(FactSales))</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">All(FactSales) blocks any columns from FactSales, but since the filter context is empty, it has no effect. When DimDate is evaluated, filter context is still empty.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">In the third formula</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">Calculate(CountRows(DimDate), Filter(All(FactSales), true))</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The All function is not at the top level of setfilter argument, table Filter(All(FactSales), true) is added to filter context, table DimDate is filtered by filter context for the same reason as in the first formula.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div>Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com56tag:blogger.com,1999:blog-8486191632104654344.post-60563909667756227962011-02-22T20:58:00.000-08:002011-03-04T17:00:36.881-08:00MDX Overwrite Semantics and Complex Attribute Relationship<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The past month has been extremely busy for me so I didn’t get to write more blogs. Today we’ll resume the exploration of MDX calculation engine. In this post I am going to describe a common mistake made by people when writing MDX calculations that can be very hard to diagnose.</span><br />
<br />
<span style="font-family: Calibri;">WARNING: The MDX overwrite behavior I am going to describe in this post applies to overwriting to a physical member or the [All] member. Overwriting to a calculated member has its own set of rules which are not covered here.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">An Example</span></span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Let’s start with a simple example using Adventure Works DW 2008 database. First create a calculated measure, [m], that returns [Internet Sales Amount] for the first quarter of fiscal year 2004.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="color: blue; font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">create</span><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"> <span style="color: blue;">member</span> [Adventure Works].[Measures].[m] <span style="color: blue;">as</span> </span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">([Internet Sales Amount], [Date].[Fiscal].[Fiscal Quarter].[Q1 FY 2004])</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Next send a query to check the value of [m].</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt 0.5in; mso-layout-grid-align: none;"><span style="color: blue; font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">select</span><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"> [m] <span style="color: blue;">on</span> 0</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="color: blue; font-family: "Courier New"; font-size: 10pt; line-height: 115%; mso-no-proof: yes;">from</span><span style="font-family: "Courier New"; font-size: 10pt; line-height: 115%; mso-no-proof: yes;"> [Adventure Works]</span></div><br />
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-bottom: medium none; border-collapse: collapse; border-left: medium none; border-right: medium none; border-top: medium none; margin: auto auto auto 0.5in; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;"><tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">m</span></div></td></tr>
<tr style="mso-yfti-irow: 1; mso-yfti-lastrow: yes;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">$2,744,340.48</span></div></td></tr>
</tbody></table><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Now send another query calculating [m] but start with different calendar quarters.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt 0.5in; mso-layout-grid-align: none;"><span style="color: blue; font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">select</span><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"> [m] <span style="color: blue;">on</span> 0,</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt 0.5in; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">[Date].[Calendar].[Calendar Quarter].<span style="color: blue;">members</span> <span style="color: blue;">on</span> 1</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="color: blue; font-family: "Courier New"; font-size: 10pt; line-height: 115%; mso-no-proof: yes;">from</span><span style="font-family: "Courier New"; font-size: 10pt; line-height: 115%; mso-no-proof: yes;"> [Adventure Works]</span></div><br />
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-bottom: medium none; border-collapse: collapse; border-left: medium none; border-right: medium none; border-top: medium none; margin: auto auto auto 0.5in; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;"><tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><br />
</div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">m</span></div></td></tr>
<tr style="mso-yfti-irow: 1;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Q3 CY 2001</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">(null)</span></div></td></tr>
<tr style="mso-yfti-irow: 2;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Q4 CY 2001</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">(null)</span></div></td></tr>
<tr style="mso-yfti-irow: 3;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Q1 CY 2002</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">(null)</span></div></td></tr>
<tr style="mso-yfti-irow: 4;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Q2 CY 2002</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">(null)</span></div></td></tr>
<tr style="mso-yfti-irow: 5;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Q3 CY 2002</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">(null)</span></div></td></tr>
<tr style="mso-yfti-irow: 6;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Q4 CY 2002</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">(null)</span></div></td></tr>
<tr style="mso-yfti-irow: 7;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Q1 CY 2003</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">(null)</span></div></td></tr>
<tr style="mso-yfti-irow: 8;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Q2 CY 2003</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">(null)</span></div></td></tr>
<tr style="mso-yfti-irow: 9;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Q3 CY 2003</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">$2,744,340.48</span></div></td></tr>
<tr style="mso-yfti-irow: 10;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Q4 CY 2003</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">(null)</span></div></td></tr>
<tr style="mso-yfti-irow: 11;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Q1 CY 2004</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">(null)</span></div></td></tr>
<tr style="mso-yfti-irow: 12;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Q2 CY 2004</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">(null)</span></div></td></tr>
<tr style="mso-yfti-irow: 13;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Q3 CY 2004</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">(null)</span></div></td></tr>
<tr style="mso-yfti-irow: 14; mso-yfti-lastrow: yes;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 77.4pt;" valign="top" width="103"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Q4 CY 2006</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 85.5pt;" valign="top" width="114"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">(null)</span></div></td></tr>
</tbody></table><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Why don’t we see the value, $2,744,340.48, in all cells? Didn’t the MDX formula of [m] change whatever calendar quarter to the first quarter of fiscal year 2004? The answer lies in MDX overwrite semantics and attribute relationship of the [Date] dimension.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Examine the Example Based on MDX Overwrite Rules</span></span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Before we delve into details, let’s establish some terminologies first. MDX attribute relationship defines functional dependency between two attributes, e.g. </span></div><div class="MsoNormal" style="margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">[Calendar Quarter] <span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;">→</span> [Calendar Semester] <span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;">→ [Calendar Year].</span></span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">If A <span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;">→</span> B, we say B is <b style="mso-bidi-font-weight: normal;">related</b> to A and A is <b style="mso-bidi-font-weight: normal;">relating</b> to B. Therefore, [Calendar Semester] and [Calendar Year] are related attributes of [Calendar Quarter], and reversely [Calendar Quarter] and [Calendar Semester] are relating attributes of [Calendar Year]. <span style="mso-spacerun: yes;"> </span>On the other hand, [Fiscal Week] and [Calendar Quarter] are not related to each other.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Every MDX expression is evaluated in a context. In a simple case, the context includes the current cell which is defined by the current coordinates of all attributes in the cube. When an MDX expression, like ([Internet Sales Amount], [Date].[Calendar Year].[CY 2004]), overwrites the coordinates of some attributes to <b style="mso-bidi-font-weight: normal;">non-All</b> members, it also <u>overwrites the coordinates of all related and relating attributes</u>. The following diagram illustrates how MDX overwrite semantics work when you set non-All slices to some attributes.</span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTfVNxpMlcCd7ANuEDD132BPWSKqJAWLc9s5UmufxByMBhkSoqyXsLR0qvVc40YHvhekDVrXHhL1IT-Js9tAmlEVszp8smfz4qBM2pEYzVAgqwKnRilbRnGQUwv0hePgX98eP_yz7MCJ4/s1600/P1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="433" j6="true" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTfVNxpMlcCd7ANuEDD132BPWSKqJAWLc9s5UmufxByMBhkSoqyXsLR0qvVc40YHvhekDVrXHhL1IT-Js9tAmlEVszp8smfz4qBM2pEYzVAgqwKnRilbRnGQUwv0hePgX98eP_yz7MCJ4/s640/P1.png" width="640" /></a></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The common mistake I referred to at the beginning of the post is when people forget about the slices left over at the unrelated attributes. When dimension autoexists is applied and the new slices set by the MDX expression do not exist with the slices left over on the unrelated attributes, you end up with cells that don’t exist. Note that we don’t have this problem when there is only a simple linear attribute relationship defined on the dimension.</span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNMa_KZiBlKbG294i3tQp-Ikd1S_WqoOaqYZLRTyAsHKwm3pHlKLUof0aa9nv1vrt17f9F0vz_FnzXWHfMlmjai0DO8OfYGagGEhx-p3fLlo6trCY4GnwSMf2fJhnkQcRCde07DHsI_10/s1600/P2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" j6="true" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNMa_KZiBlKbG294i3tQp-Ikd1S_WqoOaqYZLRTyAsHKwm3pHlKLUof0aa9nv1vrt17f9F0vz_FnzXWHfMlmjai0DO8OfYGagGEhx-p3fLlo6trCY4GnwSMf2fJhnkQcRCde07DHsI_10/s320/P2.png" width="218" /></a></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt 2in;"><span style="mso-no-proof: yes;"></span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">In case of a single linear relationship, all attributes in the dimension are always overwritten, either explicitly or implicitly, when any attribute is set to a non-All member. The problem arises only when there is a complex attribute relationship, one with tree-like structure.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Going to back to the Adventure Works example, to calculate the value of any cell, an initial cell coordinate is set to a quarter from the [Calendar] hierarchy. Moreover, all related and relating attributes are set implicitly as well. See a simplified version of attribute relationship below. Every attribute in the diagram, except for [Month Name] is set to a slice that corresponds to a calendar quarter.</span><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2bVH7Cna0KE4XM5N6rvN-sRKp3iR99fNU_wnYkn1XgqNtdFDncqGAyjmCi2g1vA1q1u47xPh-KfSZWrzlT8HlOu-8EuKDWOhSbfeipn6L2rP8_vzMlnHe2_UNT18I-gGvH9c_VGtV6yg/s1600/1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="329" l6="true" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2bVH7Cna0KE4XM5N6rvN-sRKp3iR99fNU_wnYkn1XgqNtdFDncqGAyjmCi2g1vA1q1u47xPh-KfSZWrzlT8HlOu-8EuKDWOhSbfeipn6L2rP8_vzMlnHe2_UNT18I-gGvH9c_VGtV6yg/s640/1.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br />
</div></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><shape id="_x0000_i1025" o:ole="" style="height: 147pt; width: 468pt;" type="#_x0000_t75"><imagedata o:title="" src="file:///C:\Users\jewang\AppData\Local\Temp\msohtmlclip1\01\clip_image004.emz"><span style="font-family: Calibri;"></span></imagedata></shape></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">After applying the MDX expression associated with calculated measure [m], some attribute slices change to new ones, shown as colored boxes below, other attribute slices retain the previous values, shown as white boxes below.</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;"></div></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><shape id="_x0000_i1026" o:ole="" style="height: 209.25pt; width: 468pt;" type="#_x0000_t75"><imagedata o:title="" src="file:///C:\Users\jewang\AppData\Local\Temp\msohtmlclip1\01\clip_image006.emz"><span style="font-family: Calibri;"></span></imagedata></shape></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkjgQkO6y4czESjbJ4TXtlSzzauf6sX916E00AMQ-bbB2rGCzq4BCVPTOTalVwy9YUPO6H78bz36WJGZZHQiEWt6kyJi8jp6fX1BTDoZyhEgbWqVRkw-T8e7B_KlwOWdOkpwHasfiRqJM/s1600/2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="330" l6="true" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkjgQkO6y4czESjbJ4TXtlSzzauf6sX916E00AMQ-bbB2rGCzq4BCVPTOTalVwy9YUPO6H78bz36WJGZZHQiEWt6kyJi8jp6fX1BTDoZyhEgbWqVRkw-T8e7B_KlwOWdOkpwHasfiRqJM/s640/2.png" width="640" /></a></div><span style="font-family: Calibri;">You get a valid new cell only when the new slices correspond to the first quarter of fiscal year 2004 exist with the untouched old slices derived from the original calendar quarter; otherwise you get a cell that doesn’t exist hence a NULL value for the MDX formula. In this case only the third quarter of calendar year 2003 produces valid cell coordinates. To force setting the current coordinate to the first quarter of fiscal year 2004 regardless of the current calendar quarter, you have to explicitly overwrite all attributes related to the [Calendar] hierarchy like below:</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt 0.5in; mso-layout-grid-align: none;"><span style="color: blue; font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">create</span><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"> <span style="color: blue;">member</span> [Adventure Works].[Measures].[m] <span style="color: blue;">as</span> </span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt 0.5in; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">(</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt 0.5in; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"><span style="mso-tab-count: 1;"> </span>[Internet Sales Amount], </span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt 0.5in; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"><span style="mso-tab-count: 1;"> </span>[Date].[Fiscal].[Fiscal Quarter].[Q1 FY 2004],</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt 0.5in; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"><span style="mso-tab-count: 1;"> </span>[Date].[Calendar].[All]</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt 0.5in; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">)</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Official Rules</span></span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The above example is based on overwriting the current coordinate to a non-All member. But what about the other cases? Well, the following table lists all combinations of how overwriting one attribute can affect its related or relating attributes.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Assume A <span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;">→</span> B.</span></div><br />
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-bottom: medium none; border-collapse: collapse; border-left: medium none; border-right: medium none; border-top: medium none; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 480;"><tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 149.4pt;" valign="top" width="199"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><b style="mso-bidi-font-weight: normal;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="font-family: Calibri;">Explicit Overwrite</span></span></b></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 193.5pt;" valign="top" width="258"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><b style="mso-bidi-font-weight: normal;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="font-family: Calibri;">Result</span></span></b></div></td></tr>
<tr style="mso-yfti-irow: 1;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 149.4pt;" valign="top" width="199"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="font-family: Calibri;">A.All to A.All</span></span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 193.5pt;" valign="top" width="258"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="font-family: Calibri;">B unaffected</span></span></div></td></tr>
<tr style="mso-yfti-irow: 2;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 149.4pt;" valign="top" width="199"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="font-family: Calibri;">A.x to A.All</span></span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 193.5pt;" valign="top" width="258"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="font-family: Calibri;">B to B.All</span></span></div></td></tr>
<tr style="mso-yfti-irow: 3;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 149.4pt;" valign="top" width="199"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="font-family: Calibri;">A to A.x</span></span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 193.5pt;" valign="top" width="258"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="font-family: Calibri;">B to Exists(B.members, A.x)</span></span></div></td></tr>
<tr style="mso-yfti-irow: 4;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 149.4pt;" valign="top" width="199"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="font-family: Calibri;">B.All to B.All</span></span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 193.5pt;" valign="top" width="258"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="font-family: Calibri;">A to A.All</span></span></div></td></tr>
<tr style="mso-yfti-irow: 5;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 149.4pt;" valign="top" width="199"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="font-family: Calibri;">B.x to B.All</span></span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 193.5pt;" valign="top" width="258"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="font-family: Calibri;">A to A.All</span></span></div></td></tr>
<tr style="mso-yfti-irow: 6; mso-yfti-lastrow: yes;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 149.4pt;" valign="top" width="199"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="font-family: Calibri;">B to B.x</span></span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 193.5pt;" valign="top" width="258"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="font-family: Calibri;">A to A.All</span></span></div></td></tr>
</tbody></table><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">An implicit overwrite is when an attribute is moved because of an overwrite on a relating or related attribute. When an attribute is impacted by both an explicit overwrite and an implicit overwrite, the explicit takes precedence. Implicit overwrites do not overwrite related or relating attributes.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Parent Child Dimension</span></span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">According to the overwrite rules discussed so far, overwriting the key attribute of a dimension to a non-All member should overwrite all other attributes in the dimension implicitly. But this does not work for parent child dimensions.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">If you run query</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="color: blue; font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">with</span><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"> <span style="color: blue;">member</span> measures.x <span style="color: blue;">as</span> </span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">(</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"><span style="mso-tab-count: 1;"> </span>[Measures].[Amount], </span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"><span style="mso-tab-count: 1;"> </span>[Account].[Account].[Work in Process]</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">)</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="color: blue; font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">select</span><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"> x <span style="color: blue;">on</span> 0,</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">([Account].[Account].[Raw Materials], [Account].[Account Number].[1162]) <span style="color: blue;">on</span> 1</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="color: blue; font-family: "Courier New"; font-size: 10pt; line-height: 115%; mso-no-proof: yes;">from</span><span style="font-family: "Courier New"; font-size: 10pt; line-height: 115%; mso-no-proof: yes;"> [Adventure Works]</span></div><br />
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-bottom: medium none; border-collapse: collapse; border-left: medium none; border-right: medium none; border-top: medium none; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;"><tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 81.9pt;" valign="top" width="109"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><br />
</div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 49.5pt;" valign="top" width="66"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><br />
</div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 49.5pt;" valign="top" width="66"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">x</span></div></td></tr>
<tr style="mso-yfti-irow: 1; mso-yfti-lastrow: yes;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 81.9pt;" valign="top" width="109"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Raw Materials</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 49.5pt;" valign="top" width="66"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">1162</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 49.5pt;" valign="top" width="66"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">(null)</span></div></td></tr>
</tbody></table><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">You get back null result even though the calculation overwrites the key attribute [Account]. You have to explicitly overwrite [Account Number] attribute to get back the [Amount] for [Work in Process].</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="color: blue; font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">with</span><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"> <span style="color: blue;">member</span> measures.x <span style="color: blue;">as</span> </span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">(</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"><span style="mso-tab-count: 1;"> </span>[Measures].[Amount], </span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"><span style="mso-tab-count: 1;"> </span>[Account].[Account].[Work in Process], </span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"><span style="mso-tab-count: 1;"> </span>[Account].[Account Number].[All]</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">)</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="color: blue; font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">select</span><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;"> x <span style="color: blue;">on</span> 0,</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt; mso-layout-grid-align: none;"><span style="font-family: "Courier New"; font-size: 10pt; mso-no-proof: yes;">([Account].[Account].[Raw Materials], [Account].[Account Number].[1162]) <span style="color: blue;">on</span> 1</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="color: blue; font-family: "Courier New"; font-size: 10pt; line-height: 115%; mso-no-proof: yes;">from</span><span style="font-family: "Courier New"; font-size: 10pt; line-height: 115%; mso-no-proof: yes;"> [Adventure Works]</span></div><br />
<table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-bottom: medium none; border-collapse: collapse; border-left: medium none; border-right: medium none; border-top: medium none; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;"><tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 81.9pt;" valign="top" width="109"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><br />
</div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 49.5pt;" valign="top" width="66"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><br />
</div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 81pt;" valign="top" width="108"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">x</span></div></td></tr>
<tr style="mso-yfti-irow: 1; mso-yfti-lastrow: yes;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 81.9pt;" valign="top" width="109"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Raw Materials</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 49.5pt;" valign="top" width="66"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">1162</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 81pt;" valign="top" width="108"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">$1,393,582.00</span></div></td></tr>
</tbody></table><br />
<div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The official rule here is that:</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Overwriting key attribute of parent child hierarchy does not overwrite other attributes except that of its parent.</span><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWzIeQTOlQGzLPPlqCGbvPHAYyyfFUg7fjZmgV7GZumeVTE4Ppcw6aImaX55qxV_aUMVdeXy8yHeoD2oYyDiQdENCIF_yxBBeNLMkfna5oEU2BJ2zSp7kqKTgqPOueRGqb324T4gllQQI/s1600/P3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="304" j6="true" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWzIeQTOlQGzLPPlqCGbvPHAYyyfFUg7fjZmgV7GZumeVTE4Ppcw6aImaX55qxV_aUMVdeXy8yHeoD2oYyDiQdENCIF_yxBBeNLMkfna5oEU2BJ2zSp7kqKTgqPOueRGqb324T4gllQQI/s640/P3.png" width="640" /></a></div></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="mso-no-proof: yes;"><shape id="Picture_x0020_29" o:spid="_x0000_i1028" style="height: 223.5pt; mso-wrap-style: square; visibility: visible; width: 468pt;" type="#_x0000_t75"><imagedata o:title="" src="file:///C:\Users\jewang\AppData\Local\Temp\msohtmlclip1\01\clip_image008.png"><span style="font-family: Calibri;"></span></imagedata></shape></span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Complex Relationships Are Very Common</span></span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Unless you define a single linear relationship for a dimension, you will end up with a complex relationship. Specifically, when there are more than two attributes in a dimension and you didn’t define any relationship, the default one is a tree-like relationship.</span><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicnUPUrMOPsgSgh8-zFLaLe7afnGkoUNexodJinJ2FwucBmmnbQa_l_YJIHnLoWWkL21TcYBQL0LD8JyAVemieVq6pYKSzxDbFGTuiIRQBX8ON3SH5BwZRyVARVQ9JXIt3vPzK2k8Kwkw/s1600/P4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="120" j6="true" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicnUPUrMOPsgSgh8-zFLaLe7afnGkoUNexodJinJ2FwucBmmnbQa_l_YJIHnLoWWkL21TcYBQL0LD8JyAVemieVq6pYKSzxDbFGTuiIRQBX8ON3SH5BwZRyVARVQ9JXIt3vPzK2k8Kwkw/s400/P4.png" width="400" /></a></div></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="mso-no-proof: yes;"><shape id="Picture_x0020_28" o:spid="_x0000_i1027" style="height: 103.5pt; mso-wrap-style: square; visibility: visible; width: 338.25pt;" type="#_x0000_t75"><imagedata o:title="" src="file:///C:\Users\jewang\AppData\Local\Temp\msohtmlclip1\01\clip_image010.png"><span style="font-family: Calibri;"></span></imagedata></shape></span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">MDX Writeback with Custom Weight Expression</span></span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Users are likely to make the mistake we have discussed so far when the current cell coordinates contain many slices on numerous attributes. This is particularly true when it comes to MDX writeback with custom weight expression. When an MDX UPDATE CUBE statement is sent to Analysis Services, the desired result is allocated to leaf level nodes. So if you are writing a custom weight formula, the current context is always a leaf level cell with a slice on every regular attribute. If you are not careful overwriting all attributes in a dimension, your weight expression is likely to return NULL values and you won’t get the allocation you desired.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 12pt; line-height: 115%; mso-bidi-font-size: 11.0pt;"><span style="font-family: Calibri;">Conclusion</span></span></b></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The complex rules of MDX overwrite semantics combined with a tree-like attribute relationship can easily lead to some very frustrating bugs in your MDX formula. You must make sure to overwrite slices on all attributes you don’t want to keep and preserve the slices on all attributes you do want to keep. Remember that the rules are different for parent child dimensions. If you have a simple tuple like MDX formula that returns unexpected NULLs, you should check whether you have violated the guidelines given in this blog post.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><br />
</div>Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com34tag:blogger.com,1999:blog-8486191632104654344.post-74717081408948343582011-01-17T16:33:00.000-08:002011-02-27T23:29:19.477-08:00DAX Time Intelligence Functions<div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Time intelligence functions are an advanced feature of DAX. They are typically composite functions built on top of other more basic DAX features and have more stringent requirements for the structure of the underlying database. But since time related calculations are fundamental to almost all BI projects, early adopters of DAX started using the time intelligence functions almost immediately after the first release of DAX. Due to the advanced nature of these functions, questions naturally arise about how they work and why they work that way even when people managed to get the desired results.</span></div><div class="MsoNormal" style="margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Marius Dumitru, architect of AS engine team, gave the following recipe to users of time intelligence functions.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">1.<span style="mso-tab-count: 1;"> </span>Never use the datetime column from the fact table in time functions.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">2.<span style="mso-tab-count: 1;"> </span>Always create a separate Time table with contiguous dates (i.e. without missing day gaps in the date values).</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">3.<span style="mso-tab-count: 1;"> </span>Create relationships between fact tables and the Time table.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">4.<span style="mso-tab-count: 1;"> </span>Make sure that relationships are based on a datetime column (and NOT based on another artificial key column).</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">5.<span style="mso-tab-count: 1;"> </span>Make sure you have full years’ worth of data in the Time table. For instance, even though your transaction table may only have sales data up to May 2010, the Time table should have dates up to December 2010 (same goes for fiscal years).</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">6.<span style="mso-tab-count: 1;"> </span>The datetime column in the Time table should be at day granularity (without fractions of a day).</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">In this post, I’ll expose more details behind the implementation of time intelligence functions to shed light on the rationale behind Marius’ advice. This post is meant to supplement online documentation of SQL Server 2008 R2. I will <u>not</u> cover basic usage examples of time intelligence functions in typical BI applications. DAX is a young functional language that evolves rapidly. What is covered here applies to SQL Server 2008 R2.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">I assume you are already familiar with advanced DAX concepts such as row context, filter context, Calculate function, Values function, measures, etc. I’ll start with some common features across all time intelligence functions before I delve into individual functions.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 14pt;"><span style="font-family: Calibri;">The <dates> argument</span></span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">All time intelligence functions have a special <dates> argument. FirstNonBlank and LastNonBlank operate on non-date/time columns but the conversion rules descibed below still apply. With the exception of DatesBetween and DatesInPeriod, the <dates> argument can be one of three forms:</span></div><div class="MsoListParagraphCxSpFirst" style="line-height: normal; margin: 0in 0in 0pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">1.</span><span style="font-family: "Times New Roman";"> </span></span></span><span style="font-family: Calibri;">A reference to a date/time column.</span></div><div class="MsoListParagraphCxSpMiddle" style="line-height: normal; margin: 0in 0in 0pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">2.</span><span style="font-family: "Times New Roman";"> </span></span></span><span style="font-family: Calibri;">A table expression that returns a single column of date/time values.</span></div><div class="MsoListParagraphCxSpLast" style="line-height: normal; margin: 0in 0in 10pt 0.5in; mso-list: l0 level1 lfo1; text-indent: -0.25in;"><span style="mso-bidi-font-family: Calibri; mso-bidi-theme-font: minor-latin;"><span style="mso-list: Ignore;"><span style="font-family: Calibri;">3.</span><span style="font-family: "Times New Roman";"> </span></span></span><span style="font-family: Calibri;">A boolean expression that defines a single-column table of date/time values.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Internally, all three forms are converted to a DAX table expression in the following fashion:</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"></div><table border="1" cellpadding="0" cellspacing="0" class="MsoTableGrid" style="border-bottom: medium none; border-collapse: collapse; border-left: medium none; border-right: medium none; border-top: medium none; mso-border-alt: solid windowtext .5pt; mso-padding-alt: 0in 5.4pt 0in 5.4pt; mso-yfti-tbllook: 1184;"><tbody>
<tr style="mso-yfti-firstrow: yes; mso-yfti-irow: 0;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 90.9pt;" valign="top" width="121"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Format number</span></b></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 196.4pt;" valign="top" width="262"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;"><dates> format</span></b></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: windowtext 1pt solid; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 191.5pt;" valign="top" width="255"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">Internal table expression</span></b></div></td></tr>
<tr style="mso-yfti-irow: 1;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 90.9pt;" valign="top" width="121"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">1</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 196.4pt;" valign="top" width="262"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">T[C]</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 191.5pt;" valign="top" width="255"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">CalculateTable(Values(T[C]))</span></div></td></tr>
<tr style="mso-yfti-irow: 2;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 90.9pt;" valign="top" width="121"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">2</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 196.4pt;" valign="top" width="262"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Single column table expression</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 191.5pt;" valign="top" width="255"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">As is</span></div></td></tr>
<tr style="mso-yfti-irow: 3; mso-yfti-lastrow: yes;"><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: windowtext 1pt solid; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 90.9pt;" valign="top" width="121"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">3</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 196.4pt;" valign="top" width="262"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Well-formed scalar expression</span></div></td><td style="background-color: transparent; border-bottom: windowtext 1pt solid; border-left: #f0f0f0; border-right: windowtext 1pt solid; border-top: #f0f0f0; mso-border-alt: solid windowtext .5pt; mso-border-left-alt: solid windowtext .5pt; mso-border-top-alt: solid windowtext .5pt; padding-bottom: 0in; padding-left: 5.4pt; padding-right: 5.4pt; padding-top: 0in; width: 191.5pt;" valign="top" width="255"><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 0pt;"><span style="font-family: Calibri;">Filter(All(T[C]), <scalar expression>)</span></div></td></tr>
</tbody></table><br />
<div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><br />
<span style="font-family: Calibri;">What is a well-formed scalar expression? Vaguely speaking, it is a scalar expression that DAX engine can analyze and extract a fully qualified column reference to a date/time column. <i style="mso-bidi-font-style: normal;">T[C] = Date(2011, 1, 17)</i> is a well-formed expression as DAX engine can extract T[C] from it. <i style="mso-bidi-font-style: normal;">T[C] * 2</i> is a well-formed expression for the same reason even though it is not a boolean expression DAX engine will cast it to boolean data type implicitly. <i style="mso-bidi-font-style: normal;">Date(2011, 1, 17)</i> is not a well-formed scalar expression as no column reference can be extracted from it.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Note that internally inserted CalculateTable in the first format automatically converts current row contexts to filter contexts. So</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt; text-indent: 0.5in;"><span style="font-family: Calibri;">MaxX(Distinct(DimDate[CalendarYear]), OpeningBalanceYear([m], DimDate[Datekey]))</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">will give the maximum opening balance among all years, but</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>MaxX(Distinct(DimDate[CalendarYear]), OpeningBalanceYear([m], Values(DimDate[Datekey])))</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">will not as the <dates> argument is in the second format hence not correlated to the current calendar year on the row context.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 14pt;"><span style="font-family: Calibri;">A special rule regarding datetime filter inside Calculate/CalculateTable </span></span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">If a Calculate filter has a unique column that is of data type date/time, all previous filters on all columns from the table which contains this date/time column are removed. This hacky feature implies that</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>Calculate(<expression>, <TI function>) = Calculate(<expression>, <TI function>, All(DateTable)).</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">This is the reason behind Marius’ recommendation #4. Let’s say you have some years on the pivot-table row and then you drag a measure which uses time-intelligence function DateAdd to show sales from the previous year. The author of the measure formula may not realize that DateAdd function only returns a single column of Datekey which overwrites existing filter on the same column. This special rule makes sure that the filter on the CalendarYear column, which comes from the pivot-table, is also removed so you get back the expected result. Without this special rule, Calculate(<expression>, <TI function>) would set days of the previous year on the Datekey column but leave the previous year as the filter on the CalendarYear column. The conflicting filters would have produced a blank result.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">In PowerPivot v1, the only way to mark a column as unique is to create an incoming relationship to this column, hence Marius’ recommendation #3. You obviously also need a separate Date table in order to create a relationship.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">In practice, people want to use integer keys to create relationship between Fact table and Date table. If you want to use time intelligence functions in that case, you must add All(DateTable) filter yourself to the measure expression.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">In future versions of PowerPivot, users may be able to mark a date/time column as unique without creating an incoming relationship to the column. When that happens, recommendation #3 would no longer be needed.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 14pt;"><span style="font-family: Calibri;">Calendar</span></span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">DAX engine creates an internal calendar data structure for each date/time column used in the time intelligence functions. The calendar contains a hierarchy of year-quarter-month-day. The minimum year and the maximum year in the calendar are determined by the actual dates in the date/time column. Internally, intermediate results are represented as arrays of days. So to represent January 2011, intermediate result would hold the 31 days in that month. Although a calendar contains all days in the years involved, it marks which days actually exist in the column. Calendar member functions return result days only if they are marked as exists. So if you have missing dates in the date/time column, they cannot be returned as a result of time intelligence functions.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">When a calendar data structure is initially populated, it raises an error if two values from the date/time column correspond to the same day. So if you have a date/time column below the day granularity, it cannot be used in time intelligence functions.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Obviously calendar is an internal implementation detail which is subject to change in future releases of DAX. I mention it here to explain some of the limitations imposed on the current version of time intelligence functions. I’ll refer to calendar again when I discuss individual functions next.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 14pt;"><span style="font-family: Calibri;">Primitive time intelligence functions</span></span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">As I mentioned at the beginning of the post, time intelligence functions are an advanced feature of DAX. They are built on top of other DAX features and functions, so there is nothing primitive about them. But many time-intelligence functions are composed from more basic time-intelligence functions which have their native implementations, I call the latter primitive ones.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">FirstDate/LastDate/StartOfMonth/EndOfMonth/StartOfQuarter/EndOfQuarter/StartOfYear/EndOfYear return a table of a single column and a single row. They can be used anywhere a table expression or a scalar expression is needed due to implicit table to scalar cast.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">As I described in the section on the <dates> argument, no matter which format the user uses, internally they are all converted to a table expression. From now on I will use <b style="mso-bidi-font-weight: normal;"><dates table></b> to denote the table expression equivalent to <dates>. I will use <b style="mso-bidi-font-weight: normal;">DimDate[Datekey] </b>or simply<b style="mso-bidi-font-weight: normal;"> [Datekey]</b> to denote the date/time column extracted from <dates> expression.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">FirstDate(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">LastDate(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">These two functions return a single column, single row table with values equivalent to</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>MinX(<dates table>, [Datekey]), or</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>MaxX(<dates table>, [Datekey]).</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">FirstNonBlank(<column>, <expression>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">LastNonBlank(<column>, <expression>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">These two functions are not pure time-intelligence functions as the first argument is not limited to <dates> as in all other time-intelligence functions. They are internally rewritten as</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>Top1(Filter(<column table>, Not(IsBlank(<expression>)), [column]), and</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>Bottom1(Filter(<column table>, Not(IsBlank(<expression>)), [column]) respectively.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Top1 and Bottom1 are internal functions similar to MinX and MaxX functions but support all DAX data types include boolean and string data types.</span><br />
<span style="font-family: Calibri;">Note that <expression> is not automatically wrapped in Calculate, therefore,</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>FirstNonBlank(DimDate[Datekey], Sum(FactSales[SalesAmount]))</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">does not give you what you want, but</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>FirstNonBlank(DimDate[Datekey], Calculate(Sum(FactSales[SalesAmount])))</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">will produce the expected result.</span><br />
</div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">StartOfMonth(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">StartOfQuarter(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">StartOfYear(<dates>, <year_end_date>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Although not implemented this way, these functions first find FirstDate(<dates>), then jump to first day that exists in the same month/quarter/year.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">EndOfMonth(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">EndOfQuarter(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">EndOfYear(<dates>, <year_end_date>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Although not implemented this way, these functions first find LastDate(<dates>), then jump to the last day that exists in the same month/quarter/year.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">DateAdd(<dates>, <number_of_intervals>, <interval>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">ParallelPeriod(<dates>, <number_of_intervals>, <interval>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">SamePeriodLastYear(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">SamePeriodLastYear(<dates>) is identical to DateAdd(<dates>, -1, Year).</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Both DateAdd and ParallelPeriod invoke a function, Move, on the calendar object. The only difference is that ParallelPeriod requires the result days to fill an entire month/quarter/year, while DateAdd does not have this requirement. </span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Currently, DateAdd has a limitation that <dates table> must contain continuous days so that the result days can be continuous too.<span style="mso-spacerun: yes;"> </span>We have this limitation because when you move all 28 days in February one month forward, like below, </span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>DateAdd(filter(All(DimDate[Datekey]), Year([Datekey]) = 2006 && Month([Datekey]) = 2), 1, Month)</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">you get back 31 days in March! As we mentioned in the section about Calendar, all intermediate results of time intelligence functions are represented as an array of days. So there is no difference between all days in February and February itself. But what if you have one day missing in the middle of February? Should we return one day missing in March or 27 days in March? This seems to be a tricky but less important question, so we left it undecided and raised an error instead.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The calendar object’s Move function is the most <i style="mso-bidi-font-style: normal;">intelligent</i> part of all time intelligence functions. It knows that moving both 3/30 and 3/31 one month forward end up on the same day 4/30. Internally it only moves by number of days or months, number of quarters or years is simply translated to corresponding number of months. Sometimes the Move function can be too smart for the user. When it moves a continuous range of days forward N months, it checks the start day and the end day of the range to see if you are moving whole months or just individual days. This works well when all days exist in the date/time column. But if you have missing days, the Move logic still tries to guess whether you are moving whole months based on days that exist, this may not be what you would expect, hence Marius’ recommendation #2.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">DatesBetween(<dates>, <start_date>, <end_date>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">DatesInPeriod(<dates>, <start_date>, <number_of_intervals>, <interval>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">These two functions are different from the other time intelligence functions in that the <dates> argument can only be a fully-qualified column reference to a date/time column. Note that online document incorrectly states that the <dates> argument in DatesInPeriod can be any of the three formats.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Internally, both functions are rewritten as</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>Filter(All(DimDate[Datekey]), DatesRange([Datekey], Earlier(<start_date>), Earlier(<end_date>))) or</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>Filter(All(DimDate[Datekey]), DatesRange([Datekey], Earlier(<start_date>, Earlier(<number_of_intervals>), <interval>))</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">In the formulas above, Earlier is an internal extended version of the public Earlier function that evaluates an entire DAX expression by skipping the last row context. DatesRange is an internal boolean function that returns true if the value of the first argument falls within an interval. In case of DatesRange(<date_value>, <start_date>, <end_date>), the interval is defined as [start_date, end_date]. In case of DatesRange(<date_value>, <start_date>, <number_of_intervals>, <interval>), the interval is defined as [start_date, end_date) where end_date is calculated by calling the Move function on the calendar object, so it is a smart move</span><span style="font-family: Wingdings; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-char-type: symbol; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin; mso-symbol-font-family: Wingdings;"><span style="mso-char-type: symbol; mso-symbol-font-family: Wingdings;">J</span></span><span style="font-family: Calibri;"> Note that since <number_of_intervals> can be a negative number, like when you move backwards in time, the interval specified by DatesInPeriod can be in the reverse order. DatesBetween does <u>not</u> allow reversed end points.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Also note that All(DimDate[Datekey]) implies that existing filter context does not apply to the date/time column, unlike when all other time intelligence functions use the name-pair syntax.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">PreviousDay(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">PreviousMonth(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">PreviousQuarter(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">PreviousYear(<dates>, <year_end_date>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Although not implemented this way, these function are equivalent to</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">FirstDate(DateAdd(<dates>, -1, Day)) in case of PreviousDay, or</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">DatesInPeriod(</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 1in;"><span style="font-family: Calibri;"><dates>, </span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 1in;"><span style="font-family: Calibri;">StartOfMonth/StartOfQuarter/StartOfYear(</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 1.5in;"><span style="font-family: Calibri;">DateAdd(<dates>, -1, Month/Quarter/Year)</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 1in;"><span style="font-family: Calibri;">),</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 1in;"><span style="font-family: Calibri;">1,</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 1in;"><span style="font-family: Calibri;">Month/Quarter/Year</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">) in case of PreviousMonth/PreviousQuarter/PreviousYear.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">NextDay(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">NextMonth(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">NextQuarter(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">NextYear(<dates>, <year_end_date>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">Although not implemented this way, these functions are equivalent to</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">LastDate(DateAdd(<dates>, 1, Day)) in case of NextDay, or</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">DatesInPeriod(</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 1in;"><span style="font-family: Calibri;"><dates>,</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 1in;"><span style="font-family: Calibri;">EndOfMonth/EndOfQuarter/EndOfYear(</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 1.5in;"><span style="font-family: Calibri;">DateAdd(<dates>, 1, Month/Quarter/Year)</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 1in;"><span style="font-family: Calibri;">),</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 1in;"><span style="font-family: Calibri;">-1,</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 1in;"><span style="font-family: Calibri;">Month/Quarter/Year</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt 0.5in;"><span style="font-family: Calibri;">) in case NextMonth/NextQuarter/NextYear.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 14pt;"><span style="font-family: Calibri;">Composite time intelligence functions</span></span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;">The remaining time intelligence functions listed below are always internally rewritten using other time intelligence function.</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">DatesMTD(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>DatesBetween(<dates>, StartOfMonth(LastDate(<dates>)), LastDate(<dates>))</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">DatesQTD(<dates>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>DatesBetween(<dates>, StartOfQuarter(LastDate(<dates>)), LastDate(<dates>))</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">DatesYTD(<dates>, <year_end_date>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>DatesBetween(<dates>, StartOfYear(LastDate(<dates>), <year_end_date>), LastDate(<dates>))</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">TotalMTD(<expression>, <dates>, <filter>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>Calculate(<expression>, DatesMTD(<dates>), <filter>)</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">TotalQTD(<expression>, <dates>, <filter>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>Calculate(<expression>, DatesQTD(<dates>), <filter>)</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">TotalYTD(<expression>, <dates>, <filter>, <year_end_date>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>Calculate(<expression>, DatesYTD(<dates>, <year_end_date>), <filter>)<span style="mso-tab-count: 1;"> </span></span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">OpeningBalanceMonth(<expression>, <dates>, <filter>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>Calculate(<expression>, PreviousDay(StartOfMonth(<dates>)), filter)</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">OpeningBalanceQuarter(<expression>, <dates>, <filter>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>Calculate(<expression>, PreviousDay(StartOfQuarter(<dates>)), filter)</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">OpeningBalanceYear(<expression>, <dates>, <filter>, <year_end_date>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>Calculate(<expression>, PreviousDay(StartOfYear(<dates>, <year_end_date>)), filter)</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><br />
</div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">ClosingBalanceMonth(<expression>, <dates>, <filter>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>Calculate(<expression>, EndOfMonth(<dates>), <filter>)</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">ClosingBalanceQuarter(<expression>, <dates>, <filter>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>Calculate(<expression>, EndOfQuarter(<dates>), <filter>)</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><b style="mso-bidi-font-weight: normal;"><span style="font-family: Calibri;">ClosingBalanceYear(<expression>, <dates>, <filter>, <year_end_date>)</span></b></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><span style="font-family: Calibri;"><span style="mso-tab-count: 1;"> </span>Calculate(<expression>, EndOfYear(<dates>, <year_end_date>), <filter>)</span></div><div class="MsoNormal" style="line-height: normal; margin: 0in 0in 10pt;"><br />
</div>Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com547tag:blogger.com,1999:blog-8486191632104654344.post-30663838162667650292011-01-06T15:56:00.000-08:002011-01-07T20:01:34.277-08:00Execution Plans and Plan Hints for MDX IIF Function and CASE StatementMDX IIF function, and similarly MDX CASE statement, is often a cause of performance issues during execution of MDX formulas. As a developer who worked on this feature, I'll explain the execution plans considered by the MDX formula engine (FE) in this post.<br />
<br />
<strong>Introduction to some FE concepts</strong><br />
<br />
Before I delve into IIF function, I first need to introduce some basic concepts used by MDX FE. I admit that these concepts can be very complex and are worth several dedicated blog posts. The cursory description here can only give you some general ideas to help you understand execution plans for IIF. You can skip this section directly to the discussion about IIF plans and come back here for references when you need to.<br />
<ul><li>Subspace</li>
</ul>Every MDX expression is evaluated in a current context which includes a subspace. A subspace is a subset of cells within the cube space. The original subspace is defined by the MDX query, for example, evaluate a measure expression for all product categories and all years. For a given MDX expression, FE will produce a result, like a value for scalar expressions, for every cell in the current subspace.<br />
<ul><li>Rectangular subspace vs. arbitrary-shaped subspace</li>
</ul>FE represents most subspaces in a very efficient rectangular shape which is a crossjoin of all attributes with non-trivial slices. Many common operations are fast and efficient when performed on rectangular subspaces. For example, search for a cached execution plan; determine whether a cell belongs to a subspace; decide whether an MDX scoped calculation applies to a subspace. But sometimes FE has to create arbitrary-shaped subspaces which you can imagine as rectangular subspaces plus additional constraints such as an enumerated set of tuples. { food, drink } x { 2009, 2010 } is an example of rectangular subspace. { (food, 2009), (drink, 2010) } is an example of arbitrary-shaped subspace. In general, Arbitrary-shaped subspaces are bad for performance.<br />
<ul><li>Cell-by-cell mode vs. block mode</li>
</ul>FE can evaluate a given MDX formula in cell-by-cell mode, in which case FE first builds a context for each cell in the subspace and then calculates the expression in each single-cell context, or in block mode, in which case FE builds a context which contains all cells in the subspace and evaluates the expression in a single scoop. Microsoft introduced MDX block mode execution in SQL Server 2005 and extended it to much more functions in SQL Server 2008. Typically block mode execution is orders of magnitude faster than cell-by-cell execution.<br />
<ul><li>Logical plan</li>
</ul>An MDX expression is evaluated in multiple stages, at one stage, a logical plan tree is built. If you have any SQL background, don't confuse the logical plan for an MDX expression with the logical plan of relational engine. In particular, MDX FE may need to execute some subtrees in the middle of building a large logical plan tree.<br />
<ul><li>Varying attributes</li>
</ul>The varying attributes of an MDX expression in a given subspace are those attributes that have more than one member in the subspace and on which the MDX expression depends. Varying attributes of an expression is derived after FE has built a logical plan tree for the expression.<br />
<ul><li>Sparse expression vs. dense expression</li>
</ul>An MDX scalar expression is called sparse in a subspace if most of the time it produces a single value, typically NULL. For example, physical measures are sparse in typical query subspaces consisting of crossjoin of dimensional attributes. If an MDX expression is not sparse, it is called dense.<br />
<ul><li>Default value</li>
</ul>The common single value of a sparse MDX scalar expression is called the default value of that expression. The default value of an MDX scalar expression is determined after FE has built a logical plan for the expression.<br />
<br />
<strong>Execution plans for IIF function</strong><br />
<br />
<span id="goog_457316506"></span><br />
Now we are ready to explore the execution plans of IIF. Implementation of IIF underwent a major overhaul in SQL Server 2008. In SQL Server 2005, there is limited support of block mode for most MDX functions, therefore IIF branches are more often evaluated in cell-by-cell mode. When SQL Server 2005 is able to evaluate IIF in block mode, it evaluates both branches in the original subspace with some special flag to indicate that the subspace may be too large, see eager mode below.<br />
<br />
In this post I focus on the algorithm adopted by SQL Server 2008 and above. As a first step, FE transforms a single IIF function call into nested IIF function calls by eliminating AND operators and OR operators in the predicate expression. Notice that one branch expression is duplicated as a result of this rewrite.<br />
<br />
IIF(a AND b, x, y) => IIF(a, IIF(b, x, y), y)<br />
IIF(a OR b, x, y) => IIF(a, x, IIF(b, x, y))<br />
<br />
Next, FE builds a logical plan for the simplified predicate expression. Note that FE may execute some subtrees while building a logical plan tree, this is a big topic which I have to discuss in a seperate blog post. After FE has built a logical plan tree for the predicate expression, FE performs constant folding by checking whether the simplified predicate is constant in the current subspace, and if so, reducing IIF function to one of its branch expressions.<br />
<br />
The next step is to build logical plans for the then branch expression and the else branch expression. FE can evaluate each branch expression in one of two modes: eager mode and strict mode. As mentioned before, the IIF expression is evaluated in a subspace, let's denote it as S0. FE can either evaluate the then branch expression in S0 or FE can build a new subspace, S1, by restricting S0 to those cells that the predicate is true. Similarly, FE can either evaluate the else branch expression in S0 or FE can build another new subspace, S2, by restricting S0 to those cells that the predicate is false. If FE evaluates a branch expression in the original subspace S0, we call it in eager mode. If FE evaluates a branch expression in the restricted subspace S1 or S2, we call it in strict mode.<br />
<br />
Strict mode has the obvious benefit of reducing the number of cells an expression is evaluated, so why doesn't FE choose it all the time? As it turns out, constructing a new subspace by evaluating the predicate will produce an arbitrary-shaped subspace if the varying attributes of the predicate expression contain more than one attribute. In general, arbitrary-shaped subspace can lead to bad performance due to various reasons such as cache misses. Moreover, if a branch expression is simple enough, like when it is a constant value, it doesn't make sense to build a new subspace at all.<br />
<br />
MDX gives user direct control over whether a branch is executed in eager mode or strict mode through branch hints. For example, IIF(p, x HINT EAGER, y HINT STRICT) tells FE to build logical plan in eager mode for the then branch and in strict mode for the else branch.<br />
<br />
When there is no direct hint from user, FE takes several steps to come up with a final logical plan for each branch expression. It first tries to build a logical plan for each branch in eager mode if it is cheap. It is always cheap to build a plan for a constant value expression. When branch expressions are more complex, FE looks at the varying attributes of the predicate logical plan. If the varying attributes contains more than one attribute, hence will produce an arbitrary-shaped subspace which makes an eager plan more appealing, FE first tries to build an eager logical plan tree for a branch expression if it can be cheaply done, in other words, if it can build a plan tree without executing any subtree. In the cheap mode, if at any point in the process of building a logical plan tree for a branch expression, FE finds out that it needs to execute a subtree before it can proceed, FE will abandon the process and roll back all the way to the root of the current tree. I have seen bad performance caused by this trial-and-error process when a deeply nested IIF tree recursively tried to build a cheap plan, aborted the effort, built a real plan, and then repeated this process at the next nesting level. FE may abandon a cheaply built plan when the predicate expression is sparse and a branch with a cheaply built eager plan is on the minority side. For example, if the predicate is mostly true, the else branch is on the minority side. If a branch is on the minority side and if it is dense or if its default value doesn't match the default value of the IIF expression, its cheaply built eager plan will be abandoned.<br />
<br />
At this stage, if FE still doesn't have a logical plan for a branch expression, FE will build a logical plan for that branch in strict mode. It first produces a new subspace for the branch by actually executing the predicate expression, producing a materialized list of tuples of the varying attributes of the predicate that satisfy the condition for that branch, and then applying the list of tuples to the original subspace as a new constraint. FE then generates a logical plan of the branch expression in the new subspace.<br />
<br />
As you can see, MDX FE employes a rule-based approach when building execution plans for IIF function. FE makes decisions based on sparsity and complexity of sub-expressons. Since sparisity of MDX expression is based on heuristics rather than statistics, FE may make the wrong decision which is why we need user hints.<br />
<br />
IIF functions are often deeply nested, although this may not be obvious at first glance. As mentioned earlier in the post, AND and OR operators in IIF predicate are rewritten into nested IIF calls. Searched CASE statement is internally rewritten as nested IIF calls as well. Moreover, MDX script IF statement is also internally mapped to an IIF function call. All these internal tree rewrites make deeply nested IIF trees a common phenomenon in many cube.<br />
<br />
Although MDX FE employes a complex algorithm to build a final plan for the IIF function, we can still learn some basic lessons that may help us understand performance issues associated with the function.<br />
<ul><li>Strict mode helps when a branch expression is very expensive. It can be a lot of extra data has to be read from disk for those extra cells in eager mode. It can also be a very expensive MDX scoped calculation has to be included for one unwanted cell in eager mode. Try plan HINT STRICT if you think AS fetches too much data from disk as a result of evaluating a branch in eager mode.</li>
<li>All the trial-and-errors when building the eager plan can be a source of bad performance when the same IIF function is evaluated many times, typically since the parent function chooses cell-by-cell mode, or when deeply nested IIF calls recursively try eager mode and then fall back to strict mode. Adding plan hints in this case will force FE to make up its mind right away.</li>
<li>Order of predicates in nested IIF calls can be important. A wrong condition at the top level may produce an expensive arbitrary-shaped subspace which makes it expensive to evaluate a child subtree. Or a right condition at the top may save a lot of time by eliminating the need to evaluate a more expensive condition at lower level. Keep in mind that AND and OR operators are rewritten as nested IIF so the order in AND and OR operators is important for the same reason.</li>
<li>Sometimes cell-by-cell mode can be fast especially when a top level function is in cell-by-cell mode. I have seen cases where MDX FE spends a lot of time building plans for a branch expression but never execute the plans as the IIF condition was never met. When the IIF function itself is called many times since its parent is in cell-by-cell mode, all the time FE spent on building unused plans is wasted. Here you may try an undocumented HINT LAZY which applies to all MDX expressions but only takes effect when a server config flag LazyEnabled is set to 1. Using this hint will force FE to delay evaluating the MDX expression until execution time. No logical plan is built by traversing the expression tree. <strong>WARNING</strong>: You will not get support from Microsoft if you use this hint on your own. You must get approval from Microsoft Customer Service and Support if you want to use this hint in your production system.</li>
</ul><strong>Execution plans for CASE statement</strong><br />
<br />
There are two types of CASE statements: simple case statement and search case statement.<br />
<br />
Search case statement is internally rewritten as nested IIF function calls in the following way:<br />
<br />
CASE<br />
WHEN p1 THEN e1<br />
WHEN p2 THEN e2<br />
...<br />
WHEN pN THEN eN<br />
ELSE eL<br />
END<br />
<br />
=><br />
<br />
IIF (p1, e1, IIF(p2, e2, ... IIF(pN, eN, eL)...))<br />
<br />
After the rewrite, FE executes all IIF functions according to the algorithm outlined in the previous section.<br />
<br />
SQL Server 2008 SP2 CTP1 introduced a hint for search case statement. The syntax of hint for CASE is:<br />
<br />
CASE HINT <EAGER|STRICT><br />
WHEN ... THEN ...<br />
...<br />
ELSE ...<br />
END<br />
<br />
Internally, the provided hint is propagated to all branches of all IIF functions generated during the rewrite. Afterwards, FE will use the hint in the same way as hints provided directly to an explicit IIF function.<br />
<br />
The simple case statement has an execution plan similar to that of IIF function. The main difference is that IIF function only has two branches while simple case statement has N branches. As of this writing, users cannot specify eager or strict hints to simple case statements.<br />
<br />
In summary, since MDX IIF function and CASE statement are frequently a source of performance problems, using plan hints may help you solve your problem. Note that plan hints for IIF function are only available in SQL Server 2008 and later and plan hints for search case statement are introduced after SQL Server 2008 SP2 CTP1. I have to admit trying out plan hints is like shooting in the dark due to the lack of end user tools to display MDX execution plan trees.Jeffrey Wanghttp://www.blogger.com/profile/09745744072887789758noreply@blogger.com8