<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblog.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Microsoft OLAP by Mosha Pasumansky</title><link>http://sqlblog.com/blogs/mosha/default.aspx</link><description /><dc:language>en</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>SQL PASS Summit 2008 and MS BI Conference 2008</title><link>http://sqlblog.com/blogs/mosha/archive/2008/07/31/sql-pass-summit-2008-and-ms-bi-conference-2008.aspx</link><pubDate>Fri, 01 Aug 2008 05:59:47 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:8154</guid><dc:creator>mosha</dc:creator><slash:comments>0</slash:comments><comments>http://sqlblog.com/blogs/mosha/comments/8154.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/mosha/commentrss.aspx?PostID=8154</wfw:commentRss><wfw:comment>http://sqlblog.com/blogs/mosha/rsscomments.aspx?PostID=8154</wfw:comment><description>&lt;p&gt;&lt;a href="http://summit2008.sqlpass.org/"&gt;SQL PASS Summit 2008&lt;/a&gt; and &lt;a href="http://www.msbiconference.com/Pages/default.aspx"&gt;Microsoft Business Intelligence Conference 2008&lt;/a&gt; are two major conferences targeting very similar audiences. And this year both conferences are happening in the same location very close to each other (there is just one month separating them). Thus, many SQL BI professionals are &lt;a href="http://cwebbbi.spaces.live.com/blog/cns!7B84B0F2C239489A!2033.entry"&gt;forced&lt;/a&gt; to &lt;a href="http://www.ssas-info.com/forum/viewtopic.php?f=6&amp;amp;t=209&amp;amp;start=0&amp;amp;st=0&amp;amp;sk=t&amp;amp;sd=a"&gt;choose&lt;/a&gt; which one to attend. And this time the choice is not an easy one. Here is a comparison table:&lt;/p&gt;  &lt;table cellspacing="0" cellpadding="2"&gt;     &lt;tr&gt;       &lt;td&gt;&amp;#160;&lt;/td&gt;        &lt;td&gt;SQL PASS Summit 2008&lt;/td&gt;        &lt;td&gt;Microsoft Business Intelligence Conference 2008&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;         &lt;p&gt;Keynotes&lt;/p&gt;       &lt;/td&gt;        &lt;td&gt;         &lt;p&gt;Ted Kummert, Tom Casey, David J. DeWitt&lt;/p&gt;          &lt;p&gt;&lt;a title="http://summit2008.sqlpass.org/keynotes.html" href="http://summit2008.sqlpass.org/keynotes.html"&gt;http://summit2008.sqlpass.org/keynotes.html&lt;/a&gt;&lt;/p&gt;       &lt;/td&gt;        &lt;td&gt;         &lt;p&gt;Kurt DelBene, Stephen Elop, Ted Kummert&lt;/p&gt;          &lt;p&gt;&lt;a title="http://www.msbiconference.com/pages/speakers.aspx" href="http://www.msbiconference.com/pages/speakers.aspx"&gt;http://www.msbiconference.com/pages/speakers.aspx&lt;/a&gt;&lt;/p&gt;       &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;         &lt;p&gt;Tracks&lt;/p&gt;       &lt;/td&gt;        &lt;td&gt;         &lt;ul&gt;           &lt;li&gt;Application Development &lt;/li&gt;            &lt;li&gt;Business Intelligence &lt;/li&gt;            &lt;li&gt;Database Application &lt;/li&gt;            &lt;li&gt;Professional Development &lt;/li&gt;         &lt;/ul&gt;       &lt;/td&gt;        &lt;td&gt;         &lt;ul&gt;           &lt;li&gt;Microsoft BI Platform and Infrastructure &lt;/li&gt;            &lt;li&gt;Microsoft BI Clients and Applications &lt;/li&gt;            &lt;li&gt;Deployment and Best Practices &lt;/li&gt;            &lt;li&gt;Customer and Industry Solutions &lt;/li&gt;            &lt;li&gt;Business Value of Business Intelligence &lt;/li&gt;            &lt;li&gt;Partner Training Track &lt;/li&gt;         &lt;/ul&gt;       &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;         &lt;p&gt;Sessions&lt;/p&gt;       &lt;/td&gt;        &lt;td&gt;         &lt;p&gt;Over 130 technical sessions &lt;/p&gt;         &lt;a title="http://summit2008.sqlpass.org/program-sessions.html" href="http://summit2008.sqlpass.org/program-sessions.html"&gt;http://summit2008.sqlpass.org/program-sessions.html&lt;/a&gt;&lt;/td&gt;        &lt;td&gt;         &lt;p&gt;65 breakout sessions &lt;/p&gt;         &lt;a title="http://www.msbiconference.com/pages/tracksandsessions.aspx" href="http://www.msbiconference.com/pages/tracksandsessions.aspx"&gt;http://www.msbiconference.com/pages/tracksandsessions.aspx&lt;/a&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;         &lt;p&gt;Extras&lt;/p&gt;       &lt;/td&gt;        &lt;td&gt;         &lt;p&gt;14 preconference full day seminars&lt;/p&gt;       &lt;/td&gt;        &lt;td&gt;         &lt;p&gt;Chalk talks&lt;/p&gt;       &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;         &lt;p&gt;SSAS specific sessions&lt;/p&gt;       &lt;/td&gt;        &lt;td&gt;         &lt;ul&gt;           &lt;li&gt;Optimizing Dimension Designs in SSAS , Dave Fackler &lt;/li&gt;            &lt;li&gt;Creating an SSIS, SSAS and SSRS monitoring solution with SSIS, SSAS and SSRS , Chris Webb &lt;/li&gt;            &lt;li&gt;Do It Right: Best Practices for Analysis Services 2005 and 2008, Craig Utley &lt;/li&gt;            &lt;li&gt;Troubleshooting MDX Query Performance , Stacia Misner &lt;/li&gt;            &lt;li&gt;Deep dive into MDX (precon) - Mosha Pasumansky &lt;/li&gt;         &lt;/ul&gt;       &lt;/td&gt;        &lt;td&gt;         &lt;ul&gt;           &lt;li&gt;Avoiding Common SQL Server Analysis Services Mistakes, Craig Utley &lt;/li&gt;            &lt;li&gt;Designing High Performance Cubes in SQL Server 2008 Analysis Services, T.K. Anand &lt;/li&gt;            &lt;li&gt;SQL Server Analysis Services Performance Monitoring, Carl Rabeler &lt;/li&gt;            &lt;li&gt;Manageability and Scalability Improvements in Microsoft SQL Server 2008 Analysis Services, T.K. Anand &lt;/li&gt;            &lt;li&gt;Optimizing Query Performance in Microsoft SQL Server 2008 Analysis Services, T.K. Anand &lt;/li&gt;         &lt;/ul&gt;       &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Dates&lt;/td&gt;        &lt;td&gt;November 18-21, 2008&lt;/td&gt;        &lt;td&gt;October 6-8, 2008&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Location&lt;/td&gt;        &lt;td&gt;Washington State Convention &amp;amp; Trade Center,          &lt;br /&gt;Seattle WA.&lt;/td&gt;        &lt;td&gt;Washington State Convention &amp;amp; Trade Center,          &lt;br /&gt;Seattle WA.&lt;/td&gt;     &lt;/tr&gt;   &lt;/table&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Last year MS BI Conference was criticized for lack of technical sessions, but this year the list looks pretty strong, and totally comparable to the PASS’s one. In fact, comparing the SSAS specific sessions, it’s easy to notice that there is overlap. Craig Utley’s session is probably going to be the same. Each conference also features dedicated session on MDX performance. But there is plenty of different content, of course. Each conference has its own extras. PASS packs two days of preconference seminars, which are full day sessions. MS BI Conference, on the other hand, offers so called “chalk talks”, which were very popular last year. This time they are supposedly better organized – i.e. held in the real rooms with not only whiteboard, but computer and projector as well (the list of chalk talks is supposed to be published by next week).&lt;/p&gt;  &lt;p&gt;Overall not an easy choice. Luckily for me, I don’t have to choose between the two – since both are in Seattle – I am going to attend both of them ! Actually, I have speaking engagements in both of them. In SQL PASS, I have “&lt;a href="http://summit2008.sqlpass.org/precon-mosha-pasumansky.html"&gt;Deep dive to MDX&lt;/a&gt;” preconference seminar, (the &lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/09/06/outline-of-the-deep-dive-to-mdx-pass-presentation.aspx"&gt;same one&lt;/a&gt; I was supposed to do last year, but it got &lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/09/16/pass-presentation-canceled.aspx"&gt;canceled&lt;/a&gt;). And in MS BI Conference, I will be hosting the chalk talk “Got MDX problems ? MDX Studio to the rescue !”.&lt;/p&gt;  &lt;p&gt;So make your decisions, the registrations are open ! &lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=SQL PASS Summit 2008 and MS BI Conference 2008&amp;amp;body=Seen on SQLblog.com: %0A%0A%09SQL PASS Summit 2008 and MS BI Conference 2008%0A%0Ahttp://sqlblog.com/blogs/mosha/archive/2008/07/31/sql-pass-summit-2008-and-ms-bi-conference-2008.aspx" target="_blank" title = "Email SQL PASS Summit 2008 and MS BI Conference 2008"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/mosha/archive/2008/07/31/sql-pass-summit-2008-and-ms-bi-conference-2008.aspx&amp;amp;title=SQL+PASS+Summit+2008+and+MS+BI+Conference+2008" target="_blank" title = "Submit SQL PASS Summit 2008 and MS BI Conference 2008 to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/07/31/sql-pass-summit-2008-and-ms-bi-conference-2008.aspx&amp;amp;phase=2" target="_blank" title = "Submit SQL PASS Summit 2008 and MS BI Conference 2008 to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/07/31/sql-pass-summit-2008-and-ms-bi-conference-2008.aspx&amp;amp;title=SQL+PASS+Summit+2008+and+MS+BI+Conference+2008" target="_blank" title = "Submit SQL PASS Summit 2008 and MS BI Conference 2008 to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/mosha/archive/2008/07/31/sql-pass-summit-2008-and-ms-bi-conference-2008.aspx&amp;amp;title=SQL+PASS+Summit+2008+and+MS+BI+Conference+2008" target="_blank" title = "Submit SQL PASS Summit 2008 and MS BI Conference 2008 to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/mosha/archive/2008/07/31/sql-pass-summit-2008-and-ms-bi-conference-2008.aspx&amp;amp;title=SQL+PASS+Summit+2008+and+MS+BI+Conference+2008&amp;amp;;top=1" target="_blank" title = "Add SQL PASS Summit 2008 and MS BI Conference 2008 to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=8154" width="1" height="1"&gt;</description></item><item><title>Product Volatility: Optimizing MDX with MDX Studio</title><link>http://sqlblog.com/blogs/mosha/archive/2008/07/29/product-volatility-optimizing-mdx-with-mdx-studio.aspx</link><pubDate>Wed, 30 Jul 2008 03:38:16 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:8120</guid><dc:creator>mosha</dc:creator><slash:comments>0</slash:comments><comments>http://sqlblog.com/blogs/mosha/comments/8120.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/mosha/commentrss.aspx?PostID=8120</wfw:commentRss><wfw:comment>http://sqlblog.com/blogs/mosha/rsscomments.aspx?PostID=8120</wfw:comment><description>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;In this article we will show how to take typical, everyday MDX and optimize it by simply following advices of MDX Studio Analyzer.&lt;/p&gt;  &lt;p&gt;As a starting point, I will take “&lt;a href="http://thomasianalytics.spaces.live.com/Blog/cns!B6B6A40B93AE1393!589.entry?9ad3d6b0"&gt;Product Volatility&lt;/a&gt;” example as published by Thomas Ivarson in his blog. It is a perfect example, because Thomas took a real business problem, and implemented it using very clean and straightforward MDX, just like I expect many MDX practitioners do. This MDX can be optimized, but some of these optimizations might not be obvious. Running MDX Studio Analyzer and following its advices takes the guesswork out of equation.&lt;/p&gt;  &lt;p&gt;Here is the MDX that computes total number of products, number of products with sales increased from last month and number of products with sales decreased from last month:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;WITH 
  MEMBER &lt;/span&gt;Measures.TotNumberOfProducts &lt;span style="color:blue;"&gt;AS 
    Count
    &lt;/span&gt;(
      &lt;span style="color:blue;"&gt;Descendants
      &lt;/span&gt;(
        [Product].[Product Categories].&lt;span style="color:maroon;"&gt;CurrentMember
       &lt;/span&gt;,[Product].[Product Categories].[Product]
      )
    ) 
  &lt;span style="color:blue;"&gt;MEMBER &lt;/span&gt;Measures.NumberOfSoldProductsIncreasing &lt;span style="color:blue;"&gt;AS 
    Count
    &lt;/span&gt;(
      &lt;span style="color:maroon;"&gt;Filter
      &lt;/span&gt;(
        &lt;span style="color:maroon;"&gt;NonEmpty
        &lt;/span&gt;(
          &lt;span style="color:blue;"&gt;Descendants
          &lt;/span&gt;(
            [Product].[Product Categories].&lt;span style="color:maroon;"&gt;CurrentMember
           &lt;/span&gt;,[Product].[Product Categories].[Product]
          )
         ,[Measures].[Internet Sales Amount]
        )
       ,
            (
              [Date].[Calendar].&lt;span style="color:maroon;"&gt;CurrentMember
             &lt;/span&gt;,[Measures].[Internet Sales Amount]
            )
          - 
            (
              [Date].[Calendar].&lt;span style="color:maroon;"&gt;PrevMember
             &lt;/span&gt;,[Measures].[Internet Sales Amount]
            )
        &amp;gt; 0
      )
    ) 
  &lt;span style="color:blue;"&gt;MEMBER &lt;/span&gt;Measures.NumberOfSoldProductsDecreasing &lt;span style="color:blue;"&gt;AS 
    Count
    &lt;/span&gt;(
      &lt;span style="color:maroon;"&gt;Filter
      &lt;/span&gt;(
        &lt;span style="color:maroon;"&gt;NonEmpty
        &lt;/span&gt;(
          &lt;span style="color:blue;"&gt;Descendants
          &lt;/span&gt;(
            [Product].[Product Categories].&lt;span style="color:maroon;"&gt;CurrentMember
           &lt;/span&gt;,[Product].[Product Categories].[Product]
          )
         ,[Measures].[Internet Sales Amount]
        )
       ,
            (
              [Date].[Calendar].&lt;span style="color:maroon;"&gt;CurrentMember
             &lt;/span&gt;,[Measures].[Internet Sales Amount]
            )
          - 
            (
              [Date].[Calendar].&lt;span style="color:maroon;"&gt;PrevMember
             &lt;/span&gt;,[Measures].[Internet Sales Amount]
            )
        &amp;lt; 0
      )
    ) 
&lt;span style="color:blue;"&gt;SELECT
  &lt;/span&gt;{
    [Measures].[TotNumberOfProducts]
   ,[Measures].[NumberOfSoldProductsIncreasing]
   ,[Measures].[NumberOfSoldProductsDecreasing]
  } &lt;span style="color:blue;"&gt;ON &lt;/span&gt;0
 ,[Date].[Calendar].[Month] &lt;span style="color:blue;"&gt;ON &lt;/span&gt;1
&lt;span style="color:blue;"&gt;FROM &lt;/span&gt;[Adventure Works]&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Executing this query with hot cache in MDX Studio produces the following perfmon counter statistics:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;font face="Lucida Console" size="2"&gt;Time&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 359 ms 
    &lt;br /&gt;Calc covers&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 85 

    &lt;br /&gt;Cells calculated : 7672 

    &lt;br /&gt;Sonar subcubes&amp;#160;&amp;#160; : 79 

    &lt;br /&gt;SE queries&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 76 

    &lt;br /&gt;Cache hits&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 76 

    &lt;br /&gt;Cache misses&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 3 

    &lt;br /&gt;Cache inserts&amp;#160;&amp;#160;&amp;#160; : 3 

    &lt;br /&gt;Cache lookups&amp;#160;&amp;#160;&amp;#160; : 79&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;The time looks good, but only because both the cube and the query are small. The number of SE queries should raise a red flag here. With only 114 cells in the result, why there were 76 SE queries ? Obviously, on more serious cubes, this will become a major performance issue. So, let’s run MDX Studio Analyzer and see what it has to say about this query. We get back the following list:&lt;/p&gt;

&lt;table style="border-right:1px solid;border-top:1px solid;font-size:10pt;border-left:1px solid;border-bottom:1px solid;font-family:calibri;" cellspacing="0" cellpadding="2"&gt;
    &lt;tr&gt;
      &lt;td&gt;Line&lt;/td&gt;

      &lt;td&gt;Col&lt;/td&gt;

      &lt;td&gt;Message&lt;/td&gt;

      &lt;td&gt;Link&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td style="width:50px;"&gt;3&lt;/td&gt;

      &lt;td style="width:50px;"&gt;6&lt;/td&gt;

      &lt;td&gt;If you are trying to count number of members in current selection - consider introducing special measure group for this dimension&lt;/td&gt;

      &lt;td&gt;&lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/05/27/counting-days-in-mdx.aspx"&gt;More Info&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td style="width:50px;"&gt;7&lt;/td&gt;

      &lt;td style="width:50px;"&gt;41&lt;/td&gt;

      &lt;td&gt;MDX function 'CurrentMember' may raise an error or produce non-desired result when user applies multiselect&lt;/td&gt;

      &lt;td&gt;&lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/01/13/multiselect-friendly-mdx-for-calculations-looking-at-current-coordinate.aspx"&gt;More Info&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td style="width:50px;"&gt;12&lt;/td&gt;

      &lt;td style="width:50px;"&gt;6&lt;/td&gt;

      &lt;td&gt;Consider rewriting Count(Filter(set, cond)) construct as Sum(set, summator) with summator IIF(cond, 1, NULL)&lt;/td&gt;

      &lt;td&gt;&lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/11/22/optimizing-count-filter-expressions-in-mdx.aspx"&gt;More Info&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td style="width:50px;"&gt;20&lt;/td&gt;

      &lt;td style="width:50px;"&gt;45&lt;/td&gt;

      &lt;td&gt;MDX function 'CurrentMember' may raise an error or produce non-desired result when user applies multiselect&lt;/td&gt;

      &lt;td&gt;&lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/01/13/multiselect-friendly-mdx-for-calculations-looking-at-current-coordinate.aspx"&gt;More Info&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td style="width:50px;"&gt;27&lt;/td&gt;

      &lt;td style="width:50px;"&gt;34&lt;/td&gt;

      &lt;td&gt;MDX function 'CurrentMember' may raise an error or produce non-desired result when user applies multiselect&lt;/td&gt;

      &lt;td&gt;&lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/01/13/multiselect-friendly-mdx-for-calculations-looking-at-current-coordinate.aspx"&gt;More Info&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td style="width:50px;"&gt;32&lt;/td&gt;

      &lt;td style="width:50px;"&gt;34&lt;/td&gt;

      &lt;td&gt;MDX function 'PrevMember' may raise an error or produce non-desired result when user applies multiselect&lt;/td&gt;

      &lt;td&gt;&lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/01/13/multiselect-friendly-mdx-for-calculations-looking-at-current-coordinate.aspx"&gt;More Info&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td style="width:50px;"&gt;39&lt;/td&gt;

      &lt;td style="width:50px;"&gt;6&lt;/td&gt;

      &lt;td&gt;Consider rewriting Count(Filter(set, cond)) construct as Sum(set, summator) with summator IIF(cond, 1, NULL)&lt;/td&gt;

      &lt;td&gt;&lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/11/22/optimizing-count-filter-expressions-in-mdx.aspx"&gt;More Info&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td style="width:50px;"&gt;47&lt;/td&gt;

      &lt;td style="width:50px;"&gt;45&lt;/td&gt;

      &lt;td&gt;MDX function 'CurrentMember' may raise an error or produce non-desired result when user applies multiselect&lt;/td&gt;

      &lt;td&gt;&lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/01/13/multiselect-friendly-mdx-for-calculations-looking-at-current-coordinate.aspx"&gt;More Info&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td style="width:50px;"&gt;53&lt;/td&gt;

      &lt;td style="width:50px;"&gt;14&lt;/td&gt;

      &lt;td&gt;Same expression was used before at Line 26 Column 14. Consider eliminating common subexpressions for better performance and to take advantage of cache&lt;/td&gt;

      &lt;td&gt;&amp;#160;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/table&gt;

&lt;p&gt;Let’s go over this list and fix issue by issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 3, Col 6: &lt;em&gt;If you are trying to count number of members in current selection - consider introducing special measure group for this dimension&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The link points to “&lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/05/27/counting-days-in-mdx.aspx"&gt;Counting days in MDX&lt;/a&gt;” blog. While we count here Products and not Days, the same technique applies here. These types of questions are best done not in MDX, but by introducing measure group, which only contains Products dimension, and single measure [Number Of Products] of type Count. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 7, Col 41: MDX function 'CurrentMember' may raise an error or produce non-desired result when user applies multiselect&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Now, this is no longer a problem because of how we solved the previous warning ! Indeed, if we wanted to see total number of products across Bikes and Accessories categories, we would’ve added the following WHERE clause:&lt;/p&gt;

&lt;pre&gt;WHERE {[Product].[Category].&amp;amp;[1],[Product].[Category].&amp;amp;[4]}&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;It fails with the original query, but works fine with Count measure [Number of Products]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 12/39, Col 6: Consider rewriting Count(Filter(set, cond)) construct as Sum(set, summator) with summator IIF(cond, 1, NULL)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a common construct, and as shown in the link to the “&lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/11/22/optimizing-count-filter-expressions-in-mdx.aspx"&gt;Optimizing Count(Filter(…)) expressions in MDX&lt;/a&gt;”, it performs much better if rewritten to use Sum. But before we do this rewrite, let’s take a look at the next warning:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 53, Col 14: Same expression was used before at Line 26 Column 14. Consider eliminating common subexpressions for better performance and to take advantage of cache&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If we click on this message, the expression in question is the following:&lt;/p&gt;

&lt;pre&gt;            (
              [Date].[Calendar].CurrentMember
             ,[Measures].[Internet Sales Amount]
            )
          - 
            (
              [Date].[Calendar].PrevMember
             ,[Measures].[Internet Sales Amount]
            )&lt;/pre&gt;

&lt;p&gt;Indeed, this expression represents Sales Growth, so we can isolate it into separate calculated member. But before we write the exact expression for the calculated member, let’s look deeper into the original expression. It features Count(Filter(NonEmpty(…))) construct, i.e. only products which had sales in current month are considered for increasing/decreasing calculation. I.e. even if product had sales in the previous month, but not in the current month, it won’t be counted in the number of products with decreasing sales. In order to repeat the same logic, the expression would be&lt;/p&gt;

&lt;pre&gt;  [Sales Growth] =
    IIF
    (
      IsEmpty([Measures].[Internet Sales Amount])
     ,NULL
     ,
        [Measures].[Internet Sales Amount]
      - 
        (
          [Date].[Calendar].PrevMember
         ,[Measures].[Internet Sales Amount]
        )
    ) &lt;/pre&gt;

&lt;p&gt;For more details why IIF(cond, NULL, exp) is good for performance, read “&lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/01/28/performance-of-iif-function-in-mdx.aspx"&gt;Performance of IIF function in MDX&lt;/a&gt;” blog. Now, putting all of together so far, we will get the following query:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;WITH 
  MEMBER &lt;/span&gt;[Sales Growth] &lt;span style="color:blue;"&gt;AS 
    &lt;/span&gt;&lt;span style="color:maroon;"&gt;IIF
    &lt;/span&gt;(
      &lt;span style="color:maroon;"&gt;IsEmpty&lt;/span&gt;([Measures].[Internet Sales Amount])
     ,&lt;span style="color:blue;"&gt;NULL
     &lt;/span&gt;,
        [Measures].[Internet Sales Amount]
      - 
        (
          [Date].[Calendar].&lt;span style="color:maroon;"&gt;PrevMember
         &lt;/span&gt;,[Measures].[Internet Sales Amount]
        )
    ) 
  &lt;span style="color:blue;"&gt;MEMBER &lt;/span&gt;PositiveGrowth &lt;span style="color:blue;"&gt;AS 
    &lt;/span&gt;&lt;span style="color:maroon;"&gt;IIF
    &lt;/span&gt;(
      [Measures].[Sales Growth] &amp;gt; 0
     ,1
     ,&lt;span style="color:blue;"&gt;NULL
    &lt;/span&gt;) 
  &lt;span style="color:blue;"&gt;MEMBER &lt;/span&gt;Measures.NumberOfSoldProductsIncreasing &lt;span style="color:blue;"&gt;AS 
    &lt;/span&gt;&lt;span style="color:maroon;"&gt;Sum
    &lt;/span&gt;(
      &lt;span style="color:blue;"&gt;Descendants
      &lt;/span&gt;(
        [Product].[Product Categories].&lt;span style="color:maroon;"&gt;CurrentMember
       &lt;/span&gt;,[Product].[Product Categories].[Product]
      )
     ,[Measures].[PositiveGrowth]
    ) 
  &lt;span style="color:blue;"&gt;MEMBER &lt;/span&gt;NegativeGrowth &lt;span style="color:blue;"&gt;AS 
    &lt;/span&gt;&lt;span style="color:maroon;"&gt;IIF
    &lt;/span&gt;(
      [Measures].[Sales Growth] &amp;lt; 0
     ,1
     ,&lt;span style="color:blue;"&gt;NULL
    &lt;/span&gt;) 
  &lt;span style="color:blue;"&gt;MEMBER &lt;/span&gt;Measures.NumberOfSoldProductsDecreasing &lt;span style="color:blue;"&gt;AS 
    &lt;/span&gt;&lt;span style="color:maroon;"&gt;Sum
    &lt;/span&gt;(
      &lt;span style="color:blue;"&gt;Descendants
      &lt;/span&gt;(
        [Product].[Product Categories].&lt;span style="color:maroon;"&gt;CurrentMember
       &lt;/span&gt;,[Product].[Product Categories].[Product]
      )
     ,[Measures].[NegativeGrowth]
    ) 
&lt;span style="color:blue;"&gt;SELECT
  &lt;/span&gt;{
    [Measures].[Number Of Products]
   ,[Measures].[NumberOfSoldProductsIncreasing]
   ,[Measures].[NumberOfSoldProductsDecreasing]
  } &lt;span style="color:blue;"&gt;ON &lt;/span&gt;0
 ,[Date].[Calendar].[Month] &lt;span style="color:blue;"&gt;ON &lt;/span&gt;1
&lt;span style="color:blue;"&gt;FROM &lt;/span&gt;[Adventure Works];&lt;/pre&gt;

&lt;p&gt;When executed in MDX Studio, we get the following perfmon statistics:&lt;/p&gt;

&lt;p&gt;&lt;font face="Lucida Console" size="2"&gt;Time&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 171 ms 
    &lt;br /&gt;Calc covers&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 15 

    &lt;br /&gt;Cells calculated : 1993 

    &lt;br /&gt;Sonar subcubes&amp;#160;&amp;#160; : 6 

    &lt;br /&gt;SE queries&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 3 

    &lt;br /&gt;Cache hits&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 7 

    &lt;br /&gt;Cache misses&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 5 

    &lt;br /&gt;Cache inserts&amp;#160;&amp;#160;&amp;#160; : 5 

    &lt;br /&gt;Cache lookups&amp;#160;&amp;#160;&amp;#160; : 12&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;This is now much better than before, there are only 3 SE queries. All of the performance warnings have been addressed, but we still have warnings about CurrentMember not working well with multiselect. Indeed, when we put multiselect on product categories on Bikes and Accessories, we get errors for number of increasing and decreasing products. Links to “&lt;a href="http://sqlblog.com/blogs/mosha/archive/2005/11/18/writing-multiselect-friendly-mdx-calculations.aspx"&gt;Writing multiselect friendly MDX calculations&lt;/a&gt;” and “&lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/01/13/multiselect-friendly-mdx-for-calculations-looking-at-current-coordinate.aspx"&gt;Multiselect friendly MDX for calculations looking at current coordinate&lt;/a&gt;” blogs are helpful to understand what the problem is. Unfortunately, there is no universal solution, and each case needs to be evaluated differently. &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;In this scenario, we can use apply to Sum(Descendants(…), exp) very similar technique that we applied to Count(Descendants(…)). The idea is not to use Descendants function, which forces us to use CurrentMember, which in turn fails on multiselect, but to put the expression “exp” directly on the Product attribute. In order to do that, we need to create fake measure in the measure group - “Num Products Increased”. It is bound to NULL expression, so this measure will always be NULL, and therefore won’t take any space in storage. But since this measure will have aggregation function Sum, it will properly aggregate when assigned expressions inside MDX Script.&lt;/p&gt;

&lt;p&gt;We will use MDX Studio to emulate MDX Script too (MDX Studio has a feature, where it automatically uses cube selected in the dropdown list to resolve current cube used in script statements).&lt;/p&gt;

&lt;p&gt;Here is the MDX:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;CREATE 
  &lt;/span&gt;[Sales Growth] = 
    &lt;span style="color:maroon;"&gt;IIF
    &lt;/span&gt;(
      &lt;span style="color:maroon;"&gt;IsEmpty&lt;/span&gt;([Measures].[Internet Sales Amount])
     ,&lt;span style="color:blue;"&gt;NULL
     &lt;/span&gt;,
        [Measures].[Internet Sales Amount]
      - 
        (
          [Date].[Calendar].&lt;span style="color:maroon;"&gt;PrevMember
         &lt;/span&gt;,[Measures].[Internet Sales Amount]
        )
    );&lt;/pre&gt;

&lt;pre class="code"&gt;
(
  [Product].[Product Categories].[Product]
 ,[Measures].[Num Products Increased]
) = 
  &lt;span style="color:maroon;"&gt;IIF
  &lt;/span&gt;(
    [Measures].[Sales Growth] &amp;gt; 0
   ,1
   ,&lt;span style="color:blue;"&gt;NULL
  &lt;/span&gt;);&lt;/pre&gt;

&lt;pre class="code"&gt;
&lt;span style="color:blue;"&gt;SELECT
  &lt;/span&gt;{
    [Measures].[Number Of Products]
   ,[Measures].[Num Products Increased]
  } &lt;span style="color:blue;"&gt;ON &lt;/span&gt;0
 ,[Date].[Calendar].[Month] &lt;span style="color:blue;"&gt;ON &lt;/span&gt;1
&lt;span style="color:blue;"&gt;FROM &lt;/span&gt;[Adventure Works]
&lt;span style="color:blue;"&gt;WHERE 
  &lt;/span&gt;{
    [Product].[Category].&amp;amp;[1]
   ,[Product].[Category].&amp;amp;[4]
  };&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;It’s performance characteristics are even slightly better than the query before:&lt;/p&gt;

&lt;p&gt;&lt;font face="Lucida Console" size="2"&gt;Time&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 31 ms
    &lt;br /&gt;Calc covers&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 6

    &lt;br /&gt;Cells calculated : 76

    &lt;br /&gt;Sonar subcubes&amp;#160;&amp;#160; : 1

    &lt;br /&gt;SE queries&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 1

    &lt;br /&gt;Cache hits&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 2

    &lt;br /&gt;Cache misses&amp;#160;&amp;#160;&amp;#160;&amp;#160; : 0

    &lt;br /&gt;Cache inserts&amp;#160;&amp;#160;&amp;#160; : 0

    &lt;br /&gt;Cache lookups&amp;#160;&amp;#160;&amp;#160; : 2&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Not to mention the fact that it works just fine with multiselect on products ! This is a great example, where fixing MDX to work properly in multiselect scenarios, has the side effect of improving performance. &lt;/p&gt;

&lt;p&gt;We still have warnings about PrevMember with respect to multiselect on the Time dimension. It is more difficult problem, since the definition of “Sales Growth” when there is multiselect on the Time dimension is ambiguous.&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=Product Volatility: Optimizing MDX with MDX Studio&amp;amp;body=Seen on SQLblog.com: %0A%0A%09Product Volatility: Optimizing MDX with MDX Studio%0A%0Ahttp://sqlblog.com/blogs/mosha/archive/2008/07/29/product-volatility-optimizing-mdx-with-mdx-studio.aspx" target="_blank" title = "Email Product Volatility: Optimizing MDX with MDX Studio"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/mosha/archive/2008/07/29/product-volatility-optimizing-mdx-with-mdx-studio.aspx&amp;amp;title=Product+Volatility%3a+Optimizing+MDX+with+MDX+Studio" target="_blank" title = "Submit Product Volatility: Optimizing MDX with MDX Studio to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/07/29/product-volatility-optimizing-mdx-with-mdx-studio.aspx&amp;amp;phase=2" target="_blank" title = "Submit Product Volatility: Optimizing MDX with MDX Studio to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/07/29/product-volatility-optimizing-mdx-with-mdx-studio.aspx&amp;amp;title=Product+Volatility%3a+Optimizing+MDX+with+MDX+Studio" target="_blank" title = "Submit Product Volatility: Optimizing MDX with MDX Studio to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/mosha/archive/2008/07/29/product-volatility-optimizing-mdx-with-mdx-studio.aspx&amp;amp;title=Product+Volatility%3a+Optimizing+MDX+with+MDX+Studio" target="_blank" title = "Submit Product Volatility: Optimizing MDX with MDX Studio to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/mosha/archive/2008/07/29/product-volatility-optimizing-mdx-with-mdx-studio.aspx&amp;amp;title=Product+Volatility%3a+Optimizing+MDX+with+MDX+Studio&amp;amp;;top=1" target="_blank" title = "Add Product Volatility: Optimizing MDX with MDX Studio to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=8120" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/mosha/archive/tags/performance/default.aspx">performance</category><category domain="http://sqlblog.com/blogs/mosha/archive/tags/mdx/default.aspx">mdx</category><category domain="http://sqlblog.com/blogs/mosha/archive/tags/mdx+studio/default.aspx">mdx studio</category></item><item><title>Microsoft buys DATAllegro</title><link>http://sqlblog.com/blogs/mosha/archive/2008/07/24/microsoft-buys-datallegro.aspx</link><pubDate>Thu, 24 Jul 2008 19:17:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:8024</guid><dc:creator>mosha</dc:creator><slash:comments>5</slash:comments><comments>http://sqlblog.com/blogs/mosha/comments/8024.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/mosha/commentrss.aspx?PostID=8024</wfw:commentRss><wfw:comment>http://sqlblog.com/blogs/mosha/rsscomments.aspx?PostID=8024</wfw:comment><description>&lt;P&gt;Official pressrelease: &lt;A href="http://www.datallegro.com/pr/7_24_08_microsoft_acquisition.asp"&gt;http://www.datallegro.com/pr/7_24_08_microsoft_acquisition.asp&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Curt Monash coverage: &lt;A href="http://www.dbms2.com/category/products-and-vendors/datallegro/"&gt;http://www.dbms2.com/category/products-and-vendors/datallegro/&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;This is a huge win for Microsoft Data Warehousing (and therefore BI) strategy !&lt;/P&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=Microsoft buys DATAllegro&amp;amp;body=Seen on SQLblog.com: %0A%0A%09Microsoft buys DATAllegro%0A%0Ahttp://sqlblog.com/blogs/mosha/archive/2008/07/24/microsoft-buys-datallegro.aspx" target="_blank" title = "Email Microsoft buys DATAllegro"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/mosha/archive/2008/07/24/microsoft-buys-datallegro.aspx&amp;amp;title=Microsoft+buys+DATAllegro" target="_blank" title = "Submit Microsoft buys DATAllegro to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/07/24/microsoft-buys-datallegro.aspx&amp;amp;phase=2" target="_blank" title = "Submit Microsoft buys DATAllegro to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/07/24/microsoft-buys-datallegro.aspx&amp;amp;title=Microsoft+buys+DATAllegro" target="_blank" title = "Submit Microsoft buys DATAllegro to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/mosha/archive/2008/07/24/microsoft-buys-datallegro.aspx&amp;amp;title=Microsoft+buys+DATAllegro" target="_blank" title = "Submit Microsoft buys DATAllegro to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/mosha/archive/2008/07/24/microsoft-buys-datallegro.aspx&amp;amp;title=Microsoft+buys+DATAllegro&amp;amp;;top=1" target="_blank" title = "Add Microsoft buys DATAllegro to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=8024" width="1" height="1"&gt;</description></item><item><title>Analyze MDX with MDX Studio</title><link>http://sqlblog.com/blogs/mosha/archive/2008/07/13/analyze-mdx-with-mdx-studio.aspx</link><pubDate>Mon, 14 Jul 2008 04:29:03 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:7808</guid><dc:creator>mosha</dc:creator><slash:comments>0</slash:comments><comments>http://sqlblog.com/blogs/mosha/comments/7808.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/mosha/commentrss.aspx?PostID=7808</wfw:commentRss><wfw:comment>http://sqlblog.com/blogs/mosha/rsscomments.aspx?PostID=7808</wfw:comment><description>&lt;p&gt;Always adhering to the MDX best practices could be a difficult quest to follow. While there is plenty of information out there, it is scattered across book, whitepapers, blogs, BOL, forum posts etc. And this information could be difficult to digest, and sometimes not clear how to apply in the specific scenarios. On top of that, not all the information out there is reliable. Some of it is outdated, and what used to help in one version of AS, could be bad practice in newer version. All this makes practitioner’s life very difficult. But it doesn’t have to be this way. For long time, I wanted to automate many of the checks for MDX best practices, and today I am happy to announce that this functionality is now part of MDX Studio. Starting with version 0.4.0, MDX Studio features the “Analyze” button. It goes through the MDX, analyzes it, and flags issues. To illustrate this better, let’s consider the following example:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;WITH 
 MEMBER
  &lt;/span&gt;Measures.WorkingDays &lt;span style="color:blue;"&gt;AS
    Count&lt;/span&gt;(
      &lt;span style="color:maroon;"&gt;Filter&lt;/span&gt;(
        &lt;span style="color:blue;"&gt;Descendants&lt;/span&gt;(
          [Date].[Calendar].&lt;span style="color:maroon;"&gt;CurrentMember
          &lt;/span&gt;,[Date].[Calendar].[Date]
          ,&lt;span style="color:blue;"&gt;SELF&lt;/span&gt;)
       ,  [Date].[Day of Week].&lt;span style="color:maroon;"&gt;CurrentMember&lt;/span&gt;.&lt;span style="color:blue;"&gt;Name &lt;/span&gt;&amp;lt;&amp;gt; &amp;quot;1&amp;quot;
      )
    )
 &lt;span style="color:blue;"&gt;MEMBER
  &lt;/span&gt;Measures.SalesPerWorkingDay &lt;span style="color:blue;"&gt;AS 
  &lt;/span&gt;'
    IIF(
     [Measures].[WorkingDays] IS NULL OR [Measures].[WorkingDays] = 0
     ,NULL
     ,[Measures].[Internet Sales Amount]/[Measures].[WorkingDays])
   '
&lt;span style="color:blue;"&gt;SELECT &lt;/span&gt;[Measures].[SalesPerWorkingDay]  &lt;span style="color:blue;"&gt;ON &lt;/span&gt;0
, [Date].[Calendar].[Month].&lt;span style="color:blue;"&gt;MEMBERS ON &lt;/span&gt;1
&lt;span style="color:blue;"&gt;FROM &lt;/span&gt;[Adventure Works]&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;In this example we are looking at sales per working day, where working day is defined as anything but Sunday. Let’s run Analyzer over this query and see what it will find out:&lt;/p&gt;

&lt;p&gt;
  &lt;table style="border-right:1px solid;border-top:1px solid;font-size:10pt;border-left:1px solid;border-bottom:1px solid;font-family:calibri;" align="left"&gt;
      &lt;tr&gt;
        &lt;td&gt;Line&lt;/td&gt;

        &lt;td&gt;Column&lt;/td&gt;

        &lt;td&gt;Message&lt;/td&gt;

        &lt;td&gt;Link&lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td style="width:50px;"&gt;7&lt;/td&gt;

        &lt;td style="width:50px;"&gt;30&lt;/td&gt;

        &lt;td&gt;MDX function 'CurrentMember' may raise an error or produce non-desired result when user applies multiselect&lt;/td&gt;

        &lt;td&gt;&lt;a href="http://sqlblog.com/blogs/mosha/archive/2005/11/18/writing-multiselect-friendly-mdx-calculations.aspx"&gt;More Info&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td style="width:50px;"&gt;10&lt;/td&gt;

        &lt;td style="width:50px;"&gt;33&lt;/td&gt;

        &lt;td&gt;MDX function 'CurrentMember' may raise an error or produce non-desired result when user applies multiselect&lt;/td&gt;

        &lt;td&gt;&lt;a href="http://sqlblog.com/blogs/mosha/archive/2005/11/18/writing-multiselect-friendly-mdx-calculations.aspx"&gt;More Info&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td style="width:50px;"&gt;10&lt;/td&gt;

        &lt;td style="width:50px;"&gt;47&lt;/td&gt;

        &lt;td&gt;Use IS operator to compare objects instead of comparing them by name&lt;/td&gt;

        &lt;td&gt;&lt;a href="http://sqlblog.com/blogs/mosha/archive/2004/11/04/comparing-members-in-mdx.aspx"&gt;More Info&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td style="width:50px;"&gt;4&lt;/td&gt;

        &lt;td style="width:50px;"&gt;6&lt;/td&gt;

        &lt;td&gt;Consider rewriting Count(Filter(set, cond)) construct as Sum(set, summator) with summator IIF(cond, 1, NULL)&lt;/td&gt;

        &lt;td&gt;&lt;a href="http://sqlblog.com/blogs/mosha/archive/2007/11/22/optimizing-count-filter-expressions-in-mdx.aspx"&gt;More Info&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td style="width:50px;"&gt;3&lt;/td&gt;

        &lt;td style="width:50px;"&gt;7&lt;/td&gt;

        &lt;td&gt;If you want to avoid division by zero - use 'value = 0' check, if you want to check whether cell is empty - use IsEmpty function, if you want to check that MDX member or tuple exists - use 'obj IS NULL' check&lt;/td&gt;

        &lt;td&gt;&lt;a href="http://sqlblog.com/blogs/mosha/archive/2005/06/30/how-to-check-if-cell-is-empty-in-mdx.aspx"&gt;More Info&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td style="width:50px;"&gt;2&lt;/td&gt;

        &lt;td style="width:50px;"&gt;6&lt;/td&gt;

        &lt;td&gt;Don't use single quotes for definitions of calculation Measures.SalesPerWorkingDay&lt;/td&gt;

        &lt;td&gt;&lt;a href="http://sqlblog.com/blogs/mosha/archive/2005/04/02/to-quote-or-not-to-quote-in-expressions-of-mdx-calculations.aspx"&gt;More Info&lt;/a&gt;&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/table&gt;

  &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;It is easier to navigate through the messages in the desktop edition of MDX Studio, where clicking on the message highlights the relevant portion of the MDX. Also there messages can be sorted, hidden (on right-click context menu) or copy/pasted to Excel. Messages are followed by the link to more information how the particular rule can be applied. &lt;/p&gt;

&lt;p&gt;The warning above are relatively simple, but MDX Studio Analyzer is capable of doing more sophisticated checks. Example of such check is detection of common subexpressions. For the following query&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;WITH 
 MEMBER
  &lt;/span&gt;Measures.SalesPerWorkingDay &lt;span style="color:blue;"&gt;AS 
  &lt;/span&gt;'
    IIF(
     Count(
      Filter(
        Descendants(
          [Date].[Calendar].CurrentMember
          ,[Date].[Calendar].[Date]
          ,SELF)
       ,  [Date].[Day of Week].CurrentMember.Name &amp;lt;&amp;gt; &amp;quot;1&amp;quot;
      )
    ) = 0
     ,NULL
     ,[Measures].[Internet Sales Amount]
      /
       Count(
         Filter(
           Descendants(
             [Date].[Calendar].CurrentMember
             ,[Date].[Calendar].[Date]
             ,SELF)
          ,  [Date].[Day of Week].CurrentMember.Name &amp;lt;&amp;gt; &amp;quot;1&amp;quot;
         )
       )
    )
   '
&lt;span style="color:blue;"&gt;SELECT &lt;/span&gt;[Measures].[SalesPerWorkingDay]  &lt;span style="color:blue;"&gt;ON &lt;/span&gt;0
, [Date].[Calendar].[Month].&lt;span style="color:blue;"&gt;MEMBERS ON &lt;/span&gt;1
&lt;span style="color:blue;"&gt;FROM &lt;/span&gt;[Adventure Works]&lt;/pre&gt;

&lt;p&gt;MDX Studio Analyzer will report that the exactly same Count(Filter(…)) expression was used twice:&lt;/p&gt;

&lt;table cellspacing="0" cellpadding="2"&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;font size="2"&gt;Line&lt;/font&gt;&lt;/td&gt;

      &lt;td&gt;&lt;font size="2"&gt;Column&lt;/font&gt;&lt;/td&gt;

      &lt;td&gt;&lt;font size="2"&gt;Message&lt;/font&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td&gt;&lt;font size="2"&gt;15&lt;/font&gt;&lt;/td&gt;

      &lt;td&gt;&lt;font size="2"&gt;9&lt;/font&gt;&lt;/td&gt;

      &lt;td&gt;&lt;font size="2"&gt;Same expression was used before at Line 3 Column 7. Consider eliminating common subexpressions for better performance and to take advantage of cache&lt;/font&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/table&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;The difficult choice that I faced was – for which version of Analysis Services to tailor the messages – AS2005 or AS2008. While some of the advices would stay the same, many others are different, and in some cases are contradictory. For example, in AS2005, CASE operator was never optimized, so at certain scenarios it was better to use nested IIFs, but in AS2008, CASE is as optimized as IIF, so it is preferable to nested IIFs. Another example is NON_EMPTY_BEHAVIOR property, which often times is essential to get good performance in AS2005, but usually is not needed in AS2008, and is better to be removed. With AS2005 everybody recommends replacing IIFs with SCOPE whenever possible, but it is not needed with AS2008 etc. At the end I decided to go with AS2008 only – it just feels as a better investment for the future. AS2008 should be released almost any day now, and I expect much faster migration to it from AS2005, then what we saw with migration from AS2000 to AS2005. The reason is simple – migration to AS2008 from AS2005 is very smooth – all the fundamental concepts stay the same, both client and management object models stay code compatible etc. &lt;/p&gt;

&lt;p&gt;One last thing to mention: Best practices are exactly what they are – best practices. It means, that most of the time using them you will be better off. However, they are absolute rules to be followed always. Sometimes there are exceptions from the rules. AS is a complex, feature-rich product, and MDX engine is probably the most sophisticated piece in it. Sometimes features interact in such a way, that some best practices might result in worse results. For example, one of the advices that MDX Studio will give is when it sees Filter(CrossJoin(…)), it will recommend using CrossJoin(Filter(…)) instead. It is common sense to reduce the size of the set before crossjoin’ing. But not only this is not always possible, but also there are rare cases where it would result in worse performance. So while you are encouraged to follow the best practices, always use them as a guide, and measure before and after applying the rules to make sure things do improve. &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;MDX Studio 0.4.0 is released with desktop and online versions simultaneously.&lt;/p&gt;

&lt;p&gt;Desktop version can be downloaded from: &lt;a title="http://cid-74f04d1ea28ece4e.skydrive.live.com/browse.aspx/MDXStudio/v0.4.0" href="http://cid-74f04d1ea28ece4e.skydrive.live.com/browse.aspx/MDXStudio/v0.4.0"&gt;http://cid-74f04d1ea28ece4e.skydrive.live.com/browse.aspx/MDXStudio/v0.4.0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Online version can be accessed at: &lt;a href="http://mdx.mosha.com"&gt;http://mdx.mosha.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As usual – please post your comments, suggestions, bug reports etc at &lt;a href="http://www.ssas-info.com/forum/mdx-studio-f3/"&gt;MDX Studio forum&lt;/a&gt;.&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=Analyze MDX with MDX Studio&amp;amp;body=Seen on SQLblog.com: %0A%0A%09Analyze MDX with MDX Studio%0A%0Ahttp://sqlblog.com/blogs/mosha/archive/2008/07/13/analyze-mdx-with-mdx-studio.aspx" target="_blank" title = "Email Analyze MDX with MDX Studio"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/mosha/archive/2008/07/13/analyze-mdx-with-mdx-studio.aspx&amp;amp;title=Analyze+MDX+with+MDX+Studio" target="_blank" title = "Submit Analyze MDX with MDX Studio to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/07/13/analyze-mdx-with-mdx-studio.aspx&amp;amp;phase=2" target="_blank" title = "Submit Analyze MDX with MDX Studio to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/07/13/analyze-mdx-with-mdx-studio.aspx&amp;amp;title=Analyze+MDX+with+MDX+Studio" target="_blank" title = "Submit Analyze MDX with MDX Studio to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/mosha/archive/2008/07/13/analyze-mdx-with-mdx-studio.aspx&amp;amp;title=Analyze+MDX+with+MDX+Studio" target="_blank" title = "Submit Analyze MDX with MDX Studio to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/mosha/archive/2008/07/13/analyze-mdx-with-mdx-studio.aspx&amp;amp;title=Analyze+MDX+with+MDX+Studio&amp;amp;;top=1" target="_blank" title = "Add Analyze MDX with MDX Studio to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=7808" width="1" height="1"&gt;</description></item><item><title>The simpler MDX is – the better !</title><link>http://sqlblog.com/blogs/mosha/archive/2008/07/04/the-simpler-mdx-is-the-better.aspx</link><pubDate>Sat, 05 Jul 2008 02:25:18 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:7667</guid><dc:creator>mosha</dc:creator><slash:comments>0</slash:comments><comments>http://sqlblog.com/blogs/mosha/comments/7667.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/mosha/commentrss.aspx?PostID=7667</wfw:commentRss><wfw:comment>http://sqlblog.com/blogs/mosha/rsscomments.aspx?PostID=7667</wfw:comment><description>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;Whenever I am asked “What is the single most important advice to write efficient MDX”, I always give same answer: The simpler MDX you write – typically the better performance you will get. The reasoning behind this is straightforward: If MDX is simple, it will be easier for the engine to understand and therefore to optimize it. I know that we all tend to think that we can do all kinds of tricks and outsmart engine, and sometimes it is true, but the engine becomes smarter and smarter with every release, and especially in AS2008. So the tricks which could’ve helped before, actually could be hurting more than helping.&lt;/p&gt;  &lt;p&gt;And now, it seems that I am not the only one saying that ! Mark Whitehorn (my coauthor of “&lt;a href="http://www.amazon.com/Fast-Track-MDX-Mark-Whitehorn/dp/1846281741"&gt;Fast Track to MDX&lt;/a&gt;” book) together with Keith Burns have just published a technical whitepaper “&lt;a href="http://msdn.microsoft.com/en-us/library/cc719165(SQL.100).aspx"&gt;Best Practices for Data Warehousing with SQL Server 2008&lt;/a&gt;”. This seems to be a whitepaper focused specifically on the improvements in SQL 2008, and it includes section named “&lt;a name="_Toc198032349"&gt;Write simpler MDX without worrying about performance&lt;/a&gt;”. Nice title, and in addition it has explanation of block computation mode.&lt;/p&gt;  &lt;p&gt;I have really only couple of minor comments about it:&lt;/p&gt;  &lt;p&gt;- Block computation mode was &lt;strong&gt;not&lt;/strong&gt; introduced in AS2008, it existed in AS2005 (I have plenty of examples in my blogs). AS2008 though, extended applicability of block computation mode very significantly. &lt;/p&gt;  &lt;p&gt;- Description of calculated member says that it is “running total of two consecutive years”, but the expression is not for running total, but rather for regular total, and also there is nothing specific about years in it. It will work with Month, Quarter, Day etc just as well.&lt;/p&gt;  &lt;p&gt;- I didn’t really understand the following statement “In most hierarchical structures we know that if data is present for one cell in 2003, it will be there for all cells in 2003. The trip to see if there is data for the previous period only needs to be carried out once”. I think this statement is really misleading. If data is present for one cell in 2003 – there is absolutely no guarantee that it will be present for all (even for any other) cells in 2003. The diagrams just above this statement show that in fact most of the cells don’t have data. What I think authors tried to say was that MDX function PrevMember doesn’t need to be called for every cell, because [2004].PrevMember will always result in [2003], and AS2008 is smart enough to make this evaluation only once, and then compute the entire subcube of 2003 for non-empty cells only&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;- The example uses VISIBLE=&lt;strong&gt;2&lt;/strong&gt; property on calculated member. I wonder why…&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=The simpler MDX is – the better !&amp;amp;body=Seen on SQLblog.com: %0A%0A%09The simpler MDX is – the better !%0A%0Ahttp://sqlblog.com/blogs/mosha/archive/2008/07/04/the-simpler-mdx-is-the-better.aspx" target="_blank" title = "Email The simpler MDX is – the better !"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/mosha/archive/2008/07/04/the-simpler-mdx-is-the-better.aspx&amp;amp;title=The+simpler+MDX+is+%e2%80%93+the+better+!" target="_blank" title = "Submit The simpler MDX is – the better ! to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/07/04/the-simpler-mdx-is-the-better.aspx&amp;amp;phase=2" target="_blank" title = "Submit The simpler MDX is – the better ! to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/07/04/the-simpler-mdx-is-the-better.aspx&amp;amp;title=The+simpler+MDX+is+%e2%80%93+the+better+!" target="_blank" title = "Submit The simpler MDX is – the better ! to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/mosha/archive/2008/07/04/the-simpler-mdx-is-the-better.aspx&amp;amp;title=The+simpler+MDX+is+%e2%80%93+the+better+!" target="_blank" title = "Submit The simpler MDX is – the better ! to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/mosha/archive/2008/07/04/the-simpler-mdx-is-the-better.aspx&amp;amp;title=The+simpler+MDX+is+%e2%80%93+the+better+!&amp;amp;;top=1" target="_blank" title = "Add The simpler MDX is – the better ! to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=7667" width="1" height="1"&gt;</description></item><item><title>MDX Studio Online – Format and Parse MDX</title><link>http://sqlblog.com/blogs/mosha/archive/2008/07/01/mdx-formatting-and-parsing-on-the-web-with-mdx-studio-online-edition.aspx</link><pubDate>Tue, 01 Jul 2008 06:55:04 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:7589</guid><dc:creator>mosha</dc:creator><slash:comments>0</slash:comments><comments>http://sqlblog.com/blogs/mosha/comments/7589.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/mosha/commentrss.aspx?PostID=7589</wfw:commentRss><wfw:comment>http://sqlblog.com/blogs/mosha/rsscomments.aspx?PostID=7589</wfw:comment><description>&lt;p&gt;MDX Formatting functionality &lt;a href="http://sqlblog.com/blogs/mosha/archive/2008/06/16/mdx-formatting-with-mdx-studio.aspx"&gt;debuted&lt;/a&gt; in MDX Studio 0.2.8, and judging by the amount of feedback I got on it – it became the most popular feature of MDX Studio ever ! Couple of people mentioned that for SQL formatting/beautifying needs, they would go online to sites like &lt;a href="http://www.sqlhere.com"&gt;www.sqlhere.com&lt;/a&gt;, which often do reasonable job for MDX as well. So this got me thinking that I could put MDX formatting functionality online as well. With little refactoring of MDX Studio code I was able to hack my first ever ASP.NET application, which became &lt;a href="http://mdx.mosha.com"&gt;MDX Studio Online Edition&lt;/a&gt;. This was a significant milestone, so I promoted version number to 0.3, and also promoted status from Alpha to Beta. &lt;/p&gt;  &lt;p&gt;The MDX Studio Online can be accessed at &lt;a href="http://mdx.mosha.com"&gt;http://mdx.mosha.com&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;In addition to “Format MDX” button, it also features “Parse” button, which does exactly the same as desktop version – it shows the MDX parse tree. Just like in desktop version, it can Format and Parse both queries (i.e. SELECT statements) and MDX Scripts (i.e. CREATE MEMBER/SET, SCOPE, assignments etc). &lt;strike&gt;The biggest known feature which is lacking from MDX Studio formatting – is support for comments. Currently it just ignores the comments instead of carrying them forward into formatted statements. I still didn’t figured out how to do it, but this issue tops my todo list&lt;/strike&gt;.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;&lt;strong&gt;Update:&lt;/strong&gt; Big thanks to Nick Medveditskov who also has written his own MDX Formatter application – he told me the trick he used to preserve comments in formatted MDX, and this functionality is now implemented in MDX Studio deployed online.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Being an online application – you can use it right away, without any installation, so it can be especially handful for consultants working at customer site, where software installations are not allowed. Another great benefit of it being online application, is that everybody is always on the latest code, so all the hotfixes and version upgrades go live for everybody immediately (well the downside is that if I break something, then everybody is broken right away and there is no rollback, but this would never happen to me, of course, would it ?) &lt;/p&gt;  &lt;p&gt;I would like to thanks several people who did smoke testing for this application before it went public and provided lots of very valuable feedback and advice, people from all around the world – Vladimir Stepa (Germany), &lt;a href="http://www.ssas-info.com/VidasMatelisBlog/"&gt;Vidas Matelis&lt;/a&gt; (Canada), &lt;a&gt;Greg Galloway&lt;/a&gt; (US), &lt;a href="http://geekswithblogs.net/darrengosbell/"&gt;Darren Gosbell&lt;/a&gt; (Australia), &lt;a href="http://asmdx.blogspot.com/"&gt;Ajit Singh&lt;/a&gt; (India) and &lt;a href="http://cwebbbi.spaces.live.com"&gt;Chris Webb&lt;/a&gt; (UK). After all of them gave green light to the current version, I feel OK now to release it to public. &lt;/p&gt;  &lt;p&gt;As usual please send your feedback about the tool to the MDX Studio forum at &lt;a title="http://www.ssas-info.com/forum/MDXStudio" href="http://www.ssas-info.com/forum/MDXStudio"&gt;http://www.ssas-info.com/forum/MDXStudio&lt;/a&gt;&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=MDX Studio Online – Format and Parse MDX&amp;amp;body=Seen on SQLblog.com: %0A%0A%09MDX Studio Online – Format and Parse MDX%0A%0Ahttp://sqlblog.com/blogs/mosha/archive/2008/07/01/mdx-formatting-and-parsing-on-the-web-with-mdx-studio-online-edition.aspx" target="_blank" title = "Email MDX Studio Online – Format and Parse MDX"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/mosha/archive/2008/07/01/mdx-formatting-and-parsing-on-the-web-with-mdx-studio-online-edition.aspx&amp;amp;title=MDX+Studio+Online+%e2%80%93+Format+and+Parse+MDX" target="_blank" title = "Submit MDX Studio Online – Format and Parse MDX to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/07/01/mdx-formatting-and-parsing-on-the-web-with-mdx-studio-online-edition.aspx&amp;amp;phase=2" target="_blank" title = "Submit MDX Studio Online – Format and Parse MDX to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/07/01/mdx-formatting-and-parsing-on-the-web-with-mdx-studio-online-edition.aspx&amp;amp;title=MDX+Studio+Online+%e2%80%93+Format+and+Parse+MDX" target="_blank" title = "Submit MDX Studio Online – Format and Parse MDX to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/mosha/archive/2008/07/01/mdx-formatting-and-parsing-on-the-web-with-mdx-studio-online-edition.aspx&amp;amp;title=MDX+Studio+Online+%e2%80%93+Format+and+Parse+MDX" target="_blank" title = "Submit MDX Studio Online – Format and Parse MDX to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/mosha/archive/2008/07/01/mdx-formatting-and-parsing-on-the-web-with-mdx-studio-online-edition.aspx&amp;amp;title=MDX+Studio+Online+%e2%80%93+Format+and+Parse+MDX&amp;amp;;top=1" target="_blank" title = "Add MDX Studio Online – Format and Parse MDX to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=7589" width="1" height="1"&gt;</description></item><item><title>Analysis Services protocol – official documentation</title><link>http://sqlblog.com/blogs/mosha/archive/2008/06/30/analysis-services-protocol-official-documentation.aspx</link><pubDate>Mon, 30 Jun 2008 21:57:37 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:7582</guid><dc:creator>mosha</dc:creator><slash:comments>0</slash:comments><comments>http://sqlblog.com/blogs/mosha/comments/7582.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/mosha/commentrss.aspx?PostID=7582</wfw:commentRss><wfw:comment>http://sqlblog.com/blogs/mosha/rsscomments.aspx?PostID=7582</wfw:comment><description>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;One of my most popular blog posts was “&lt;a href="http://sqlblog.com/blogs/mosha/archive/2005/12/02/analysis-services-2005-protocol-xmla-over-tcp-ip.aspx"&gt;Analysis Services 2005 protocol - XMLA over TCP/IP&lt;/a&gt;”. Previously this information wasn’t available from anywhere else. But things changed today. Microsoft now has engaged in the “&lt;a href="http://msdn.microsoft.com/en-us/library/cc216514.aspx"&gt;Open Specification program&lt;/a&gt;”. Citing from the web page:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;Microsoft is providing open connections to its high-volume products—Windows Vista (including the .NET Framework), Windows Server 2008, SQL Server 2008, Office 2007, Exchange Server 2007, and Office SharePoint Server 2007—as well as additional information so that software developers, business partners and competitors can better interact with these Microsoft products or invent new solutions for customers.&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;As a developer, you now have full access to information about protocols, binary file formats, and other specifications for these products that can be used to create solutions.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;(Yes, these include Office file format specifications!)&lt;/p&gt;  &lt;p&gt;Since Analysis Services is part of SQL Server, the protocols for accessing Analysis Services are listed under “&lt;a href="http://msdn.microsoft.com/en-us/library/cc678150.aspx"&gt;Microsoft SQL Server Protocols&lt;/a&gt;”. The most interesting one is &lt;/p&gt;  &lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc676961.aspx"&gt;[MS-SSAS9]: SQL Server Analysis Services Protocol Specification&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;which documents Analysis Services 2005 protocol (and 2008 as well, since protocol didn’t change between these versions). &lt;/p&gt;  &lt;p&gt;There is also&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc676956.aspx"&gt;[MS-SSAS8]: SQL Server Analysis Services Protocol Specification&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;which documents Analysis Services 2000 protocol. However, this one would be much harder to go through, since AS2000 had “smart client” architecture, where client code was doing lots of work – MDX parsing, evaluation, caching etc – therefore the protocol between client and server is at much lower level than MDX queries and it is not easy to make sense out of it.&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=Analysis Services protocol – official documentation&amp;amp;body=Seen on SQLblog.com: %0A%0A%09Analysis Services protocol – official documentation%0A%0Ahttp://sqlblog.com/blogs/mosha/archive/2008/06/30/analysis-services-protocol-official-documentation.aspx" target="_blank" title = "Email Analysis Services protocol – official documentation"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/mosha/archive/2008/06/30/analysis-services-protocol-official-documentation.aspx&amp;amp;title=Analysis+Services+protocol+%e2%80%93+official+documentation" target="_blank" title = "Submit Analysis Services protocol – official documentation to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/06/30/analysis-services-protocol-official-documentation.aspx&amp;amp;phase=2" target="_blank" title = "Submit Analysis Services protocol – official documentation to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/06/30/analysis-services-protocol-official-documentation.aspx&amp;amp;title=Analysis+Services+protocol+%e2%80%93+official+documentation" target="_blank" title = "Submit Analysis Services protocol – official documentation to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/mosha/archive/2008/06/30/analysis-services-protocol-official-documentation.aspx&amp;amp;title=Analysis+Services+protocol+%e2%80%93+official+documentation" target="_blank" title = "Submit Analysis Services protocol – official documentation to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/mosha/archive/2008/06/30/analysis-services-protocol-official-documentation.aspx&amp;amp;title=Analysis+Services+protocol+%e2%80%93+official+documentation&amp;amp;;top=1" target="_blank" title = "Add Analysis Services protocol – official documentation to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=7582" width="1" height="1"&gt;</description></item><item><title>MDX Formatting with MDX Studio</title><link>http://sqlblog.com/blogs/mosha/archive/2008/06/16/mdx-formatting-with-mdx-studio.aspx</link><pubDate>Mon, 16 Jun 2008 23:20:23 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:7329</guid><dc:creator>mosha</dc:creator><slash:comments>2</slash:comments><comments>http://sqlblog.com/blogs/mosha/comments/7329.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/mosha/commentrss.aspx?PostID=7329</wfw:commentRss><wfw:comment>http://sqlblog.com/blogs/mosha/rsscomments.aspx?PostID=7329</wfw:comment><description>&lt;p&gt;Darren Gosbell put up a &lt;a href="http://geekswithblogs.net/darrengosbell/archive/2008/06/15/a-rose-by-any-other-name---mdx-formatting.aspx"&gt;blog post&lt;/a&gt; about MDX Formatting, where he describes how he prefers to format MDX to look nice on the screen. So I thought – why to leave to a human something that machine can do. I decided to implement these rules (with some modifications) into MDX Studio. It became MDX Studio 0.2.8 release, available immediately for download at &lt;a title="http://cid-74f04d1ea28ece4e.skydrive.live.com/browse.aspx/MDXStudio/v0.2.8" href="http://cid-74f04d1ea28ece4e.skydrive.live.com/browse.aspx/MDXStudio/v0.2.8"&gt;http://cid-74f04d1ea28ece4e.skydrive.live.com/browse.aspx/MDXStudio/v0.2.8&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;I only had couple of hours to work on it, so it is rough on the edges, and I will appreciate comments in the MDX Studio forum at &lt;a title="http://www.ssas-info.com/forum/MDXStudio" href="http://www.ssas-info.com/forum/MDXStudio"&gt;http://www.ssas-info.com/forum/MDXStudio&lt;/a&gt;. But basic staff like calculated members, named sets, subselects etc should work. (One known exception is set aliases).&lt;/p&gt;  &lt;p&gt;The functionality is accessible through MDX –&amp;gt; Format menu. Here is example from Darren’s blog&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;with member &lt;/span&gt;&lt;span style="color:black;"&gt;measures&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;ptd &lt;/span&gt;&lt;span style="color:blue;"&gt;as &lt;/span&gt;&lt;span style="color:black;"&gt;'&lt;/span&gt;&lt;span style="color:darkred;"&gt;sum&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:darkred;"&gt;periodstodate&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Date]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Calendar]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Month]&lt;/span&gt;&lt;span style="color:gray;"&gt;,
&lt;/span&gt;&lt;span style="color:black;"&gt;[Date]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Calendar]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:darkred;"&gt;currentmember&lt;/span&gt;&lt;span style="color:gray;"&gt;),&lt;/span&gt;&lt;span style="color:black;"&gt;[Measures]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Sales Amount] &lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;'&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:black;"&gt;format_string &lt;/span&gt;&lt;span style="color:gray;"&gt;= &lt;/span&gt;&lt;span style="color:red;"&gt;&amp;quot;currency&amp;quot;
&lt;/span&gt;&lt;span style="color:blue;"&gt;select   &lt;/span&gt;&lt;span style="color:black;"&gt;{[Measures]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Measures]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Sales Amount] &lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:black;"&gt;measures&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;ptd} &lt;/span&gt;&lt;span style="color:blue;"&gt;on &lt;/span&gt;&lt;span style="color:magenta;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;,
&lt;/span&gt;&lt;span style="color:black;"&gt;{[Date]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Calendar]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Month]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;&amp;amp;[2003]&amp;amp;[2]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:darkred;"&gt;children&lt;/span&gt;&lt;span style="color:black;"&gt;} &lt;/span&gt;&lt;span style="color:blue;"&gt;on &lt;/span&gt;&lt;span style="color:magenta;"&gt;1 &lt;/span&gt;&lt;span style="color:blue;"&gt;from &lt;/span&gt;&lt;span style="color:black;"&gt;[Adventure Works] &lt;/span&gt;&lt;span style="color:blue;"&gt;where 
&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product Categories]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Category]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;&amp;amp;[1]&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;And here is how it looks after autoformatting:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="background:white;color:black;"&gt;&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;WITH
  MEMBER &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;measures&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;ptd &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;AS 
    &lt;/span&gt;&lt;span style="background:white;color:darkred;"&gt;sum&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;(
      &lt;/span&gt;&lt;span style="background:white;color:darkred;"&gt;periodstodate&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;(
        &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Date]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Calendar]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Month]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;,
        &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Date]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Calendar]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:darkred;"&gt;currentmember&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;),
      &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Measures]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Sales Amount]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;) 
    
    , &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;format_string &lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;= &lt;/span&gt;&lt;span style="background:white;color:red;"&gt;&amp;quot;currency&amp;quot;
&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;SELECT
  &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;{
    [Measures]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Measures]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Sales Amount]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;,
    &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;measures&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;ptd
  } &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;ON &lt;/span&gt;&lt;span style="background:white;color:magenta;"&gt;0&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;,
  &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Date]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Calendar]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Month]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;amp;[2003]&amp;amp;[2]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:darkred;"&gt;children &lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;ON &lt;/span&gt;&lt;span style="background:white;color:magenta;"&gt;1
&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;FROM &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Adventure Works]
&lt;/span&gt;&lt;span style="background:white;color:blue;"&gt;WHERE 
  &lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Product Categories]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;[Category]&lt;/span&gt;&lt;span style="background:white;color:gray;"&gt;.&lt;/span&gt;&lt;span style="background:white;color:black;"&gt;&amp;amp;[1]
&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=MDX Formatting with MDX Studio&amp;amp;body=Seen on SQLblog.com: %0A%0A%09MDX Formatting with MDX Studio%0A%0Ahttp://sqlblog.com/blogs/mosha/archive/2008/06/16/mdx-formatting-with-mdx-studio.aspx" target="_blank" title = "Email MDX Formatting with MDX Studio"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/mosha/archive/2008/06/16/mdx-formatting-with-mdx-studio.aspx&amp;amp;title=MDX+Formatting+with+MDX+Studio" target="_blank" title = "Submit MDX Formatting with MDX Studio to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/06/16/mdx-formatting-with-mdx-studio.aspx&amp;amp;phase=2" target="_blank" title = "Submit MDX Formatting with MDX Studio to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/06/16/mdx-formatting-with-mdx-studio.aspx&amp;amp;title=MDX+Formatting+with+MDX+Studio" target="_blank" title = "Submit MDX Formatting with MDX Studio to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/mosha/archive/2008/06/16/mdx-formatting-with-mdx-studio.aspx&amp;amp;title=MDX+Formatting+with+MDX+Studio" target="_blank" title = "Submit MDX Formatting with MDX Studio to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/mosha/archive/2008/06/16/mdx-formatting-with-mdx-studio.aspx&amp;amp;title=MDX+Formatting+with+MDX+Studio&amp;amp;;top=1" target="_blank" title = "Add MDX Formatting with MDX Studio to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=7329" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/mosha/archive/tags/mdx+studio/default.aspx">mdx studio</category></item><item><title>No OLAP Market shares for 2007</title><link>http://sqlblog.com/blogs/mosha/archive/2008/06/16/no-olap-market-shares-for-2007.aspx</link><pubDate>Mon, 16 Jun 2008 16:12:50 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:7320</guid><dc:creator>mosha</dc:creator><slash:comments>1</slash:comments><comments>http://sqlblog.com/blogs/mosha/comments/7320.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/mosha/commentrss.aspx?PostID=7320</wfw:commentRss><wfw:comment>http://sqlblog.com/blogs/mosha/rsscomments.aspx?PostID=7320</wfw:comment><description>&lt;p&gt;Every year around March or April I am looking forward the &lt;a href="http://www.olapreport.com/"&gt;OLAP Report&lt;/a&gt; site to see the OLAP market share numbers. Computing these numbers is not a simple task as Nigel Pendse explains on &lt;a title="http://www.olapreport.com/market.htm" href="http://www.olapreport.com/market.htm"&gt;http://www.olapreport.com/market.htm&lt;/a&gt;, and this kind of analysis really is not available anywhere else. This year again, I was waiting for the 2007 results to see by how much Microsoft increased its market share. March and April passed, then May passed, we are well into June, and the results didn’t show up. So I contacted Nigel, and here is what he told me (publishing with permission):&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;Mosha,&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;Unfortunately, I don't think it's possible to calculate accurate OLAP market shares any more. Applix, Business Objects, Cognos and Hyperion were all acquired in the last year, and therefore no longer publish figures, so it's no longer possible to work out their OLAP revenues. Furthermore, in the year of acquisition, their figures are particularly distorted (sales people work very hard to close deals just before the acquisition, because they don't expect to keep the commission afterwards, so sales are high the quarter before the deals close, and weak the following quarter).&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;Of, course, the disruption doesn't help sales in those companies, so I don't doubt that Microsoft increased its lead, its just that I don't have any good way any longer of calculating it. Generally, the new owners of those companies are not prepared to disclose product revenues.&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;Regards&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;Nigel&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;So after the wave of last year consolidations, it is no longer possible to have accurate estimates. But even without precise numbers, how the future looks like ? (emphasis is mine)&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;I may try again in the future, but at the moment, I can't think of a reliable way to calculate OLAP market shares. &lt;/em&gt;&lt;em&gt;I think it's also less interesting than in the past, with fewer significant vendors remaining. &lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;&lt;strong&gt;Microsoft is clearly going to stay #1&lt;/strong&gt;. &lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;Oracle+Hyperion will probably stay at #2, but its share is unlikely to rise.&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;IBM (Cognos+Applix) will stay at number 3; its share may rise a bit, particularly if IBM gives TM1 the promotion that Applix could not afford to do, but I think IBM will stay in #3. &lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;SAP+BOBJ will stay in the next position.&lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;MicroStrategy may gain share, but is unlikely to overtake SAP+BOBJ. &lt;/em&gt;&lt;/p&gt;    &lt;p&gt;&lt;em&gt;No other vendor comes close, so the top five aren't likely to change position any time soon.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Anyway, the picture below shows how the market share trends looked like until 2006 (source: OLAP Report)&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.olapreport.com/images/MarketShareTrend2006.png" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Calculating the market shares for consolidated companies based on 2006 positions&lt;/p&gt;  &lt;table cellspacing="0" cellpadding="2"&gt;     &lt;tr&gt;       &lt;td&gt;&amp;#160;&lt;/td&gt;        &lt;td&gt;2006 Market share&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Microsoft&lt;/td&gt;        &lt;td&gt;31.6%&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Oracle+Hyperion&lt;/td&gt;        &lt;td&gt;21.7%&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Cognos+Applix=IBM&lt;/td&gt;        &lt;td&gt;16.5%&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;SAP+Business Objects&lt;/td&gt;        &lt;td&gt;13.1%&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Microstrategy&lt;/td&gt;        &lt;td&gt;7.3%&lt;/td&gt;     &lt;/tr&gt;   &lt;/table&gt;  &lt;p&gt;&lt;strong&gt;Update: &lt;/strong&gt;Turns out the numbers in this table are not accurate, because I forgot to account that Business Objects had acquired Cartesis and that SAP had acquired OutlookSoft. Anyway, Nigel has updated his &lt;a href="http://www.olapreport.com/market.htm"&gt;OLAP market share&lt;/a&gt; page with deeper analysis of 2007 consolidation effect on market shares, and he has more accurate numbers.&lt;/p&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=No OLAP Market shares for 2007&amp;amp;body=Seen on SQLblog.com: %0A%0A%09No OLAP Market shares for 2007%0A%0Ahttp://sqlblog.com/blogs/mosha/archive/2008/06/16/no-olap-market-shares-for-2007.aspx" target="_blank" title = "Email No OLAP Market shares for 2007"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/mosha/archive/2008/06/16/no-olap-market-shares-for-2007.aspx&amp;amp;title=No+OLAP+Market+shares+for+2007" target="_blank" title = "Submit No OLAP Market shares for 2007 to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/06/16/no-olap-market-shares-for-2007.aspx&amp;amp;phase=2" target="_blank" title = "Submit No OLAP Market shares for 2007 to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/06/16/no-olap-market-shares-for-2007.aspx&amp;amp;title=No+OLAP+Market+shares+for+2007" target="_blank" title = "Submit No OLAP Market shares for 2007 to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/mosha/archive/2008/06/16/no-olap-market-shares-for-2007.aspx&amp;amp;title=No+OLAP+Market+shares+for+2007" target="_blank" title = "Submit No OLAP Market shares for 2007 to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/mosha/archive/2008/06/16/no-olap-market-shares-for-2007.aspx&amp;amp;title=No+OLAP+Market+shares+for+2007&amp;amp;;top=1" target="_blank" title = "Add No OLAP Market shares for 2007 to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=7320" width="1" height="1"&gt;</description></item><item><title>Counting distinct values in MDX</title><link>http://sqlblog.com/blogs/mosha/archive/2008/06/14/counting-distinct-values-in-mdx.aspx</link><pubDate>Sun, 15 Jun 2008 00:13:01 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:7296</guid><dc:creator>mosha</dc:creator><slash:comments>9</slash:comments><comments>http://sqlblog.com/blogs/mosha/comments/7296.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/mosha/commentrss.aspx?PostID=7296</wfw:commentRss><wfw:comment>http://sqlblog.com/blogs/mosha/rsscomments.aspx?PostID=7296</wfw:comment><description>&lt;p&gt;How many elements in the set have distinct values ? This sounds like a simple question. Apparently, this is well known problem in Excel, and there is a classic solution for it. There are plenty of sites in Internet (for example &lt;a href="http://www.mrexcel.com/archive/Formulas/18882.html"&gt;here&lt;/a&gt; and &lt;a href="http://www.j-walk.com/ss/excel/usertips/tip061.htm"&gt;here&lt;/a&gt;) which give the following solution:&lt;/p&gt;  &lt;pre&gt;=SUM(1/COUNTIF(A1:A6,A1:A6)))&lt;/pre&gt;

&lt;p&gt;(note that this formula needs to be entered with Ctrl-Shift-Enter to indicate that this is array formula, or it won’t give right result – one of the Excel quirks)&lt;/p&gt;

&lt;p&gt;When someone showed me this solution, I just stared at it and I couldn’t understand how it worked. Only rewriting it in MDX clarified what was going on. Let’s take the following example based on Adventure Works – we want to count how different letters the product names start from (just wanted to pick something for which Product dimension didn’t have dedicated attribute, because otherwise it would’ve been too simple). The MDX which performs the same algorithm as Excel formula above in these conditions will look like following:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;with 
  member measures.&lt;/span&gt;&lt;span style="color:black;"&gt;CountDistinctLetters &lt;/span&gt;&lt;span style="color:blue;"&gt;as 
   &lt;/span&gt;&lt;span style="color:darkred;"&gt;Sum&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;MEMBERS AS &lt;/span&gt;&lt;span style="color:black;"&gt;AllProducts&lt;/span&gt;&lt;span style="color:gray;"&gt;,
       &lt;/span&gt;&lt;span style="color:magenta;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;/&lt;/span&gt;&lt;span style="color:darkred;"&gt;Filter&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;MEMBERS&lt;/span&gt;&lt;span style="color:gray;"&gt;, 
          &lt;/span&gt;&lt;span style="color:black;"&gt;VBA!Left&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;AllProducts&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:darkred;"&gt;Current&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;Name&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:magenta;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;) = &lt;/span&gt;&lt;span style="color:black;"&gt;VBA!Left&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:darkred;"&gt;CurrentMember&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;Name&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:magenta;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;)
         ).&lt;/span&gt;&lt;span style="color:blue;"&gt;Count&lt;/span&gt;&lt;span style="color:gray;"&gt;)

&lt;/span&gt;&lt;span style="color:blue;"&gt;select &lt;/span&gt;&lt;span style="color:black;"&gt;CountDistinctLetters &lt;/span&gt;&lt;span style="color:blue;"&gt;on &lt;/span&gt;&lt;span style="color:magenta;"&gt;0
&lt;/span&gt;&lt;span style="color:blue;"&gt;from &lt;/span&gt;&lt;span style="color:black;"&gt;[Adventure Works]
&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;It is more verbose, but probably it is not simpler to understand to normal developer than the Excel’s formula. In the nutshell the idea is following: For every element in the set, we compute how many other elements produce the same value (this is COUNTIF in Excel, and Filter(…).Count in MDX), and then dividing 1 by this number we get fraction of current element. The summing up all these fractions will give the desired number. &lt;/p&gt;

&lt;p&gt;(Unfortunately there is no easy way to debug such formulas. The MDX debugger inside &lt;a href="http://www.mosha.com/msolap/mdxstudio.htm"&gt;MDX Studio&lt;/a&gt; is not capable of dealing with such expressions. I actually spent quite a time thinking about how to build decent environment for debugging MDX, and after few failed starts I had what I consider as breakthrough idea. Early experiments were very encouraging, and if this idea works, I will blog soon about it. It radically different from all other MDX debugging attempts.)&lt;/p&gt;

&lt;p&gt;It is clear that performance of such solution is horrible. For every element in the set, we go again and again over all elements in the set just to find out how many of them have same value. The algorithmic complexity of this nested loop approach is &lt;em&gt;O(n^2)&lt;/em&gt;. Indeed the query above executes for 12 seconds. It is possible to slightly improve it, by forcing caching the results of VBA!Left through&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;with 
  member &lt;/span&gt;&lt;span style="color:black;"&gt;Prefix &lt;/span&gt;&lt;span style="color:blue;"&gt;as &lt;/span&gt;&lt;span style="color:black;"&gt;VBA!Left&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:darkred;"&gt;CurrentMember&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;Name&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:magenta;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;)
  &lt;/span&gt;&lt;span style="color:blue;"&gt;member &lt;/span&gt;&lt;span style="color:black;"&gt;measures&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;CountDistinctLetters &lt;/span&gt;&lt;span style="color:blue;"&gt;as 
   &lt;/span&gt;&lt;span style="color:darkred;"&gt;Sum&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;MEMBERS AS &lt;/span&gt;&lt;span style="color:black;"&gt;AllProducts&lt;/span&gt;&lt;span style="color:gray;"&gt;,
       &lt;/span&gt;&lt;span style="color:magenta;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;/&lt;/span&gt;&lt;span style="color:darkred;"&gt;Filter&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;MEMBERS&lt;/span&gt;&lt;span style="color:gray;"&gt;, 
          (&lt;/span&gt;&lt;span style="color:black;"&gt;AllProducts&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:darkred;"&gt;Current&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:black;"&gt;Prefix&lt;/span&gt;&lt;span style="color:gray;"&gt;) = &lt;/span&gt;&lt;span style="color:black;"&gt;Prefix
         &lt;/span&gt;&lt;span style="color:gray;"&gt;).&lt;/span&gt;&lt;span style="color:blue;"&gt;Count&lt;/span&gt;&lt;span style="color:gray;"&gt;)

&lt;/span&gt;&lt;span style="color:blue;"&gt;select &lt;/span&gt;&lt;span style="color:black;"&gt;CountDistinctLetters &lt;/span&gt;&lt;span style="color:blue;"&gt;on &lt;/span&gt;&lt;span style="color:magenta;"&gt;0
&lt;/span&gt;&lt;span style="color:blue;"&gt;from &lt;/span&gt;&lt;span style="color:black;"&gt;[Adventure Works]&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;and reducing time to 11 seconds, but obviously, different, more sane approach is needed here.&lt;/p&gt;

&lt;p&gt;Another idea is instead of doing nested-loop algorithm, sort the elements of the set, and then scan sorted set once counting number of different elements. The only technical difficulty with that would be - while scaning sorted set, we need to compare current element with the previous one. Getting current element is easy, but how to get previous one ? There is no &amp;quot;Previous&amp;quot; function in MDX, there is only PrevMember, but it works on hierarchical ordering of the level, and here we have arbitrary set sorted by arbitrary criteria. The solution is to use CurrentOrdinal function, which returns the index of the tuple being iterated in the set, and then using CurrentOrdinal-1 as a new index, send it to Item function. In MDX this would be recorded as &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;with
  member &lt;/span&gt;&lt;span style="color:black;"&gt;Prefix &lt;/span&gt;&lt;span style="color:blue;"&gt;as &lt;/span&gt;&lt;span style="color:black;"&gt;VBA!Left&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:darkred;"&gt;CurrentMember&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;Name&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:magenta;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;)
  &lt;/span&gt;&lt;span style="color:blue;"&gt;set &lt;/span&gt;&lt;span style="color:black;"&gt;ProductsSortedByPrefix &lt;/span&gt;&lt;span style="color:blue;"&gt;as &lt;/span&gt;&lt;span style="color:darkred;"&gt;order&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;MEMBERS&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;Prefix&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:blue;"&gt;BASC&lt;/span&gt;&lt;span style="color:gray;"&gt;)
  &lt;/span&gt;&lt;span style="color:blue;"&gt;member &lt;/span&gt;&lt;span style="color:black;"&gt;measures&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;CountDistinctLetters  &lt;/span&gt;&lt;span style="color:blue;"&gt;as &lt;/span&gt;&lt;span style="color:darkred;"&gt;Sum&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;ProductsSortedByPrefix &lt;/span&gt;&lt;span style="color:blue;"&gt;as &lt;/span&gt;&lt;span style="color:black;"&gt;y&lt;/span&gt;&lt;span style="color:gray;"&gt;, 
    &lt;/span&gt;&lt;span style="color:darkred;"&gt;iif&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;y&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:darkred;"&gt;CurrentOrdinal &lt;/span&gt;&lt;span style="color:gray;"&gt;= &lt;/span&gt;&lt;span style="color:magenta;"&gt;1 &lt;/span&gt;&lt;span style="color:blue;"&gt;OR &lt;/span&gt;&lt;span style="color:black;"&gt;Prefix &lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;lt;&amp;gt; (&lt;/span&gt;&lt;span style="color:black;"&gt;Prefix&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;y&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;Item&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;y&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:darkred;"&gt;CurrentOrdinal&lt;/span&gt;&lt;span style="color:gray;"&gt;-&lt;/span&gt;&lt;span style="color:magenta;"&gt;2&lt;/span&gt;&lt;span style="color:gray;"&gt;)), &lt;/span&gt;&lt;span style="color:magenta;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:magenta;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;))

&lt;/span&gt;&lt;span style="color:blue;"&gt;select &lt;/span&gt;&lt;span style="color:black;"&gt;CountDistinctLetters  &lt;/span&gt;&lt;span style="color:blue;"&gt;on &lt;/span&gt;&lt;span style="color:magenta;"&gt;0
&lt;/span&gt;&lt;span style="color:blue;"&gt;from &lt;/span&gt;&lt;span style="color:black;"&gt;[Adventure Works]&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;This query executes much faster now, in only 0.234 seconds. The algorithmic complexity is down to &lt;em&gt;O(n*log(n))&lt;/em&gt;. However, it is still not perfect solution, since it is possible to solve this in just one scan of the original set, i.e. with &lt;em&gt;O(n)&lt;/em&gt; complexity. In order to do that, we will have to write stored procedure though. &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public int &lt;/span&gt;CountDistinctValues(&lt;span style="color:#2b91af;"&gt;Set &lt;/span&gt;set, &lt;span style="color:#2b91af;"&gt;Expression &lt;/span&gt;exp)
{
    System.Collections.&lt;span style="color:#2b91af;"&gt;Hashtable &lt;/span&gt;ht = &lt;span style="color:blue;"&gt;new &lt;/span&gt;System.Collections.&lt;span style="color:#2b91af;"&gt;Hashtable&lt;/span&gt;();
    &lt;span style="color:blue;"&gt;foreach &lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;Tuple &lt;/span&gt;t &lt;span style="color:blue;"&gt;in &lt;/span&gt;set.Tuples)
    {
        &lt;span style="color:blue;"&gt;string &lt;/span&gt;v = exp.Calculate(t).ToString();
        &lt;span style="color:blue;"&gt;if &lt;/span&gt;( !ht.ContainsKey(v) )
            ht.Add(v, &lt;span style="color:blue;"&gt;null&lt;/span&gt;);
    }

    &lt;span style="color:blue;"&gt;return &lt;/span&gt;ht.Count;
}&lt;/pre&gt;

&lt;p&gt;Now, if we use this stored procedure in the query as following&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;with member &lt;/span&gt;&lt;span style="color:black;"&gt;CountDistinctLetters &lt;/span&gt;&lt;span style="color:blue;"&gt;as &lt;/span&gt;&lt;span style="color:black;"&gt;ASSP&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;ASStoredProcs&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;Util&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;CountDistinctValues&lt;/span&gt;&lt;span style="color:gray;"&gt;(
  &lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;MEMBERS&lt;/span&gt;&lt;span style="color:gray;"&gt;,
  &lt;/span&gt;&lt;span style="color:black;"&gt;VBA!Left&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:darkred;"&gt;CurrentMember&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;Name&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:magenta;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;))
&lt;/span&gt;&lt;span style="color:blue;"&gt;select &lt;/span&gt;&lt;span style="color:black;"&gt;CountDistinctLetters &lt;/span&gt;&lt;span style="color:blue;"&gt;on &lt;/span&gt;&lt;span style="color:magenta;"&gt;0
&lt;/span&gt;&lt;span style="color:blue;"&gt;from &lt;/span&gt;&lt;span style="color:black;"&gt;[Adventure Works] &lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&lt;span style="color:black;"&gt;we get it working in only 0.062 seconds.&lt;/span&gt;&lt;/p&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=Counting distinct values in MDX&amp;amp;body=Seen on SQLblog.com: %0A%0A%09Counting distinct values in MDX%0A%0Ahttp://sqlblog.com/blogs/mosha/archive/2008/06/14/counting-distinct-values-in-mdx.aspx" target="_blank" title = "Email Counting distinct values in MDX"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/mosha/archive/2008/06/14/counting-distinct-values-in-mdx.aspx&amp;amp;title=Counting+distinct+values+in+MDX" target="_blank" title = "Submit Counting distinct values in MDX to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/06/14/counting-distinct-values-in-mdx.aspx&amp;amp;phase=2" target="_blank" title = "Submit Counting distinct values in MDX to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/06/14/counting-distinct-values-in-mdx.aspx&amp;amp;title=Counting+distinct+values+in+MDX" target="_blank" title = "Submit Counting distinct values in MDX to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/mosha/archive/2008/06/14/counting-distinct-values-in-mdx.aspx&amp;amp;title=Counting+distinct+values+in+MDX" target="_blank" title = "Submit Counting distinct values in MDX to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/mosha/archive/2008/06/14/counting-distinct-values-in-mdx.aspx&amp;amp;title=Counting+distinct+values+in+MDX&amp;amp;;top=1" target="_blank" title = "Add Counting distinct values in MDX to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=7296" width="1" height="1"&gt;</description><category domain="http://sqlblog.com/blogs/mosha/archive/tags/mdx/default.aspx">mdx</category><category domain="http://sqlblog.com/blogs/mosha/archive/tags/stored+procedure/default.aspx">stored procedure</category></item><item><title>BI Survey 8</title><link>http://sqlblog.com/blogs/mosha/archive/2008/06/13/bi-survey-8.aspx</link><pubDate>Sat, 14 Jun 2008 05:28:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:7284</guid><dc:creator>mosha</dc:creator><slash:comments>1</slash:comments><comments>http://sqlblog.com/blogs/mosha/comments/7284.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/mosha/commentrss.aspx?PostID=7284</wfw:commentRss><wfw:comment>http://sqlblog.com/blogs/mosha/rsscomments.aspx?PostID=7284</wfw:comment><description>&lt;P&gt;BI Survey 8 is up and ready to accept participants. It’s hard to believe that we are at version 8 of what started as OLAP Survey 1 back in 2000. (On the other hand, my daughter also recently turned 8, she was born in 2000 too, and I still cannot believe that she is so big now, just finished second grade, it seems only yesterday she was a little baby). Anyway, over these years the OLAP/BI Survey has grown and matured, and every year many people including myself await the results and then carefully study them. So I encourage everybody to fill it, whether you use Microsoft OLAP, or some other OLAP system, whether you are happy or dissatisfied with it. More inputs – the better. Below is the official invitation from Nigel and Co:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;We would very much welcome your participation in The BI Survey, conducted annually by Nigel Pendse. This is the largest independent survey of business intelligence/OLAP users&lt;I&gt; &lt;/I&gt;worldwide&lt;I&gt;.&lt;/I&gt; The Survey will obtain input from a large number of organizations to better understand their buying decisions, the implementation cycle and the business success achieved. Both business and technical users, as well as vendors and consultants, are welcome. &lt;/P&gt;
&lt;P&gt;The BI Survey is strictly independent. While Microsoft and other vendors assist by inviting users to participate in the Survey, the vendors do not sponsor the survey, nor influence the questionnaire design or survey results. You will be able to answer questions on your usage of a BI product from any vendor. Your data will only be used anonymously, and no personal details will be passed to vendors or other third parties.&lt;/P&gt;
&lt;P&gt;As a participant, you will not only have the opportunity to ensure your experiences are included in the analyses, but you will also receive a summary of the results from the full survey. You will also have a chance of winning one of ten $50 Amazon vouchers. Click here to complete the survey on-line. &lt;/P&gt;
&lt;P&gt;English version: &lt;A href="http://www.eu-survey.com/BI_8/BI.asp?lan=1&amp;amp;lin=22"&gt;http://www.eu-survey.com/BI_8/BI.asp?lan=1&amp;amp;lin=22&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;German version: &lt;A href="http://www.eu-survey.com/BI_8/BI.asp?lan=2&amp;amp;lin=120"&gt;http://www.eu-survey.com/BI_8/BI.asp?lan=2&amp;amp;lin=120&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Spanish version: &lt;A href="http://www.eu-survey.com/BI_8/BI.asp?lan=3&amp;amp;lin=213"&gt;http://www.eu-survey.com/BI_8/BI.asp?lan=3&amp;amp;lin=213&lt;/A&gt;&lt;A href="http://www.eu-survey.com/BI_8/BI.asp?lan=3"&gt;&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BR&gt;&lt;div class = "shareblock"&gt;&lt;span class = "shareblockTitle"&gt;Share this post:&lt;/span&gt;&lt;span class = "shareblockLink"&gt; &lt;a href = "mailto:?subject=BI Survey 8&amp;amp;body=Seen on SQLblog.com: %0A%0A%09BI Survey 8%0A%0Ahttp://sqlblog.com/blogs/mosha/archive/2008/06/13/bi-survey-8.aspx" target="_blank" title = "Email BI Survey 8"&gt;email it!&lt;/a&gt; |  &lt;a href = "http://del.icio.us/post?url=http://sqlblog.com/blogs/mosha/archive/2008/06/13/bi-survey-8.aspx&amp;amp;title=BI+Survey+8" target="_blank" title = "Submit BI Survey 8 to del.icio.us"&gt;bookmark it!&lt;/a&gt; |  &lt;a href = "http://www.digg.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/06/13/bi-survey-8.aspx&amp;amp;phase=2" target="_blank" title = "Submit BI Survey 8 to digg.com"&gt;digg it!&lt;/a&gt; |  &lt;a href = "http://reddit.com/submit?url=http://sqlblog.com/blogs/mosha/archive/2008/06/13/bi-survey-8.aspx&amp;amp;title=BI+Survey+8" target="_blank" title = "Submit BI Survey 8 to reddit.com"&gt;reddit!&lt;/a&gt; |  &lt;a href = "http://www.dotnetkicks.com/submit/?url=http://sqlblog.com/blogs/mosha/archive/2008/06/13/bi-survey-8.aspx&amp;amp;title=BI+Survey+8" target="_blank" title = "Submit BI Survey 8 to DotNetKicks"&gt;kick it!&lt;/a&gt; |  &lt;a href = "https://favorites.live.com/quickadd.aspx?marklet=1&amp;amp;mkt=en-us&amp;amp;url=http://sqlblog.com/blogs/mosha/archive/2008/06/13/bi-survey-8.aspx&amp;amp;title=BI+Survey+8&amp;amp;;top=1" target="_blank" title = "Add BI Survey 8 to Live Bookmarks"&gt;live it!&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://info.sqlblog.com/a.aspx?ZoneID=0&amp;BannerID=12&amp;AdvertiserID=1&amp;CampaignID=12&amp;Task=Get&amp;Mode=TEXT&amp;SiteID=1&amp;RandomNumber=463323" width="1" height="1" border="0"&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=7284" width="1" height="1"&gt;</description></item><item><title>Follow up on NextAnalytics challenge</title><link>http://sqlblog.com/blogs/mosha/archive/2008/06/10/follow-up-on-nextanalytics-challenge.aspx</link><pubDate>Wed, 11 Jun 2008 05:28:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:7241</guid><dc:creator>mosha</dc:creator><slash:comments>5</slash:comments><comments>http://sqlblog.com/blogs/mosha/comments/7241.aspx</comments><wfw:commentRss>http://sqlblog.com/blogs/mosha/commentrss.aspx?PostID=7241</wfw:commentRss><wfw:comment>http://sqlblog.com/blogs/mosha/rsscomments.aspx?PostID=7241</wfw:comment><description>&lt;h1&gt;&lt;/h1&gt;  &lt;p&gt;My post “&lt;a href="http://sqlblog.com/blogs/mosha/archive/2008/06/08/mdx-answer-to-nextanalytics-challenge.aspx"&gt;MDX answer to NextAnalytics challenge&lt;/a&gt;” triggered some very active discussion, and I would like to address some of the comments&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;a href="http://cwebbbi.spaces.live.com/"&gt;&lt;em&gt;Chris Webb&lt;/em&gt;&lt;/a&gt;&lt;em&gt; said:        &lt;br /&gt;I've done a fair amount of teaching MDX and the truth is that people do find even the basics very difficult to understand, but my feeling is that the problem people have with MDX is not the language as such but thinking a) multidimensionally and b) in sets. The question is then, does Ward's new language solve either of these problems? Or has he reinvented the wheel?&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I agree with the a) part, but not with the b) part. Thinking multidimensional is hard and take some time to get used to. However thinking in sets is not hard at all. SQL language is mostly based on relational algebra and uses sets extensively. Practitioners don’t find sets difficult. &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;a href="http://thomasianalytics.spaces.live.com/"&gt;&lt;em&gt;Thomas Ivarsson&lt;/em&gt;&lt;/a&gt;&lt;em&gt; said:        &lt;br /&gt;Can you publish the entire script at the end of this blog post? My conclusion is that we need better clients that can create these analytics sets at run time. End users will never do this and it is impossible to create all sets that the business users would like to have. It will fill up a cube in no time.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I am pessimistic that we will ever see such sophisticated clients. If they were in demand, we would’ve already had them. I am afraid the users will have to code such analytics either using MDX or NextAnalytics script or something else. End users don’t have any problem building such sets in Excel, so maybe Excel is our hope ?&lt;/p&gt;  &lt;p&gt;Here is the entire script:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color:green;"&gt;// Nextanalytics challenge

// calculate the rolling six month average 
&lt;/span&gt;&lt;span style="color:blue;"&gt;CREATE &lt;/span&gt;&lt;span style="color:black;"&gt;Rolling6MonthAverage;
&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;Rolling6MonthAverage&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;[Date]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Month Name]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Month Name]&lt;/span&gt;&lt;span style="color:gray;"&gt;) 
  = &lt;/span&gt;&lt;span style="color:darkred;"&gt;Avg&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Date]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Month Name]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:blue;"&gt;Lag&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:magenta;"&gt;5&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;:[Date]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Month Name]&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;[Measures]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Internet Sales Amount]&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;;
  
&lt;/span&gt;&lt;span style="color:green;"&gt;// calcualte the growth of that 
&lt;/span&gt;&lt;span style="color:blue;"&gt;CREATE &lt;/span&gt;&lt;span style="color:black;"&gt;GrowthOfRolling6MonthAverage &lt;/span&gt;&lt;span style="color:gray;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;Rolling6MonthAverage &lt;/span&gt;&lt;span style="color:gray;"&gt;- (&lt;/span&gt;&lt;span style="color:black;"&gt;Rolling6MonthAverage&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;[Date]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Month Name]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:darkred;"&gt;PrevMember&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;;

&lt;/span&gt;&lt;span style="color:green;"&gt;// calculate growth
&lt;/span&gt;&lt;span style="color:blue;"&gt;CREATE &lt;/span&gt;&lt;span style="color:black;"&gt;GrowthOfSales &lt;/span&gt;&lt;span style="color:gray;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;[Measures]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Internet Sales Amount] &lt;/span&gt;&lt;span style="color:gray;"&gt;- (&lt;/span&gt;&lt;span style="color:black;"&gt;[Measures]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Internet Sales Amount]&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;[Date]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Month Name]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:darkred;"&gt;PrevMember&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;;

&lt;/span&gt;&lt;span style="color:green;"&gt;// count each &amp;quot;growth&amp;quot; calc to the row average 
&lt;/span&gt;&lt;span style="color:blue;"&gt;CREATE &lt;/span&gt;&lt;span style="color:black;"&gt;HowManyTimeGrowthExceededRollingAverage &lt;/span&gt;&lt;span style="color:gray;"&gt;= 
  &lt;/span&gt;&lt;span style="color:blue;"&gt;Count&lt;/span&gt;&lt;span style="color:gray;"&gt;(
    &lt;/span&gt;&lt;span style="color:darkred;"&gt;Filter&lt;/span&gt;&lt;span style="color:gray;"&gt;((&lt;/span&gt;&lt;span style="color:black;"&gt;[Date]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Calendar Year]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;&amp;amp;[2003]&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:black;"&gt;[Date]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Month Name]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Month Name]&lt;/span&gt;&lt;span style="color:gray;"&gt;), &lt;/span&gt;&lt;span style="color:black;"&gt;GrowthOfSales &lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color:black;"&gt;GrowthOfRolling6MonthAverage&lt;/span&gt;&lt;span style="color:gray;"&gt;))&lt;/span&gt;&lt;span style="color:black;"&gt;;

&lt;/span&gt;&lt;span style="color:blue;"&gt;CREATE SET &lt;/span&gt;&lt;span style="color:black;"&gt;ProductsThatGrewFasterThanRollingAverageMore6OrMoreTimes &lt;/span&gt;&lt;span style="color:blue;"&gt;AS
 &lt;/span&gt;&lt;span style="color:darkred;"&gt;Generate&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Customer]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Customer Geography]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Country]&lt;/span&gt;&lt;span style="color:gray;"&gt;, 
    &lt;/span&gt;&lt;span style="color:darkred;"&gt;CrossJoin&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Customer]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Customer Geography]&lt;/span&gt;&lt;span style="color:gray;"&gt;,
      &lt;/span&gt;&lt;span style="color:darkred;"&gt;Filter&lt;/span&gt;&lt;span style="color:gray;"&gt;(
        &lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Product]&lt;/span&gt;&lt;span style="color:gray;"&gt;, 
        &lt;/span&gt;&lt;span style="color:black;"&gt;HowManyTimeGrowthExceededRollingAverage &lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;gt;= &lt;/span&gt;&lt;span style="color:magenta;"&gt;6
      &lt;/span&gt;&lt;span style="color:gray;"&gt;)
    )
  )&lt;/span&gt;&lt;span style="color:black;"&gt;;

&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT &lt;/span&gt;&lt;span style="color:black;"&gt;{} &lt;/span&gt;&lt;span style="color:blue;"&gt;ON &lt;/span&gt;&lt;span style="color:magenta;"&gt;0
&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;ProductsThatGrewFasterThanRollingAverageMore6OrMoreTimes &lt;/span&gt;&lt;span style="color:blue;"&gt;ON &lt;/span&gt;&lt;span style="color:magenta;"&gt;1
&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM &lt;/span&gt;&lt;span style="color:black;"&gt;[Adventure Works]

&lt;/span&gt;&lt;span style="color:green;"&gt;// create growth from start to end of period
&lt;/span&gt;&lt;span style="color:blue;"&gt;CREATE &lt;/span&gt;&lt;span style="color:black;"&gt;GrowthFromStartToEnd &lt;/span&gt;&lt;span style="color:gray;"&gt;=
  (&lt;/span&gt;&lt;span style="color:black;"&gt;[Measures]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Internet Sales Amount]&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:darkred;"&gt;ClosingPeriod&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;[Date]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Calendar]&lt;/span&gt;&lt;span style="color:gray;"&gt;.&lt;/span&gt;&lt;span style="color:black;"&gt;[Month]&lt;/span&gt;&lt;span style="color:gray;"&