<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Boyan Penev on Microsoft BI &#187; SSAS</title>
	<atom:link href="http://www.bp-msbi.com/category/10-ssas/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.bp-msbi.com</link>
	<description>A practical blog about Microsoft BI tools, techniques and practices written by a developer for other fellow developers.</description>
	<lastBuildDate>Sun, 29 Jan 2012 03:23:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>SSAS Locale Identifier Bug</title>
		<link>http://www.bp-msbi.com/2012/01/ssas-locale-identifier-bug/</link>
		<comments>http://www.bp-msbi.com/2012/01/ssas-locale-identifier-bug/#comments</comments>
		<pubDate>Sun, 29 Jan 2012 03:23:06 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[SSAS]]></category>
		<category><![CDATA[bug]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=472</guid>
		<description><![CDATA[These days I have two little problems with SSAS. One is really small &#8211; I really don&#8217;t like how the Process dialog in BIDS (2008 R2) stays blank during the process operation and how I need to click on &#8220;Stop&#8221; after it finishes. The fact that such a bug had gotten into the product and [...]]]></description>
			<content:encoded><![CDATA[<p>These days I have two little problems with SSAS. One is really small &#8211; I really don&#8217;t like how the Process dialog in BIDS (2008 R2) stays blank during the process operation and how I need to click on &#8220;Stop&#8221; after it finishes. The fact that such a bug had gotten into the product and has survived for so long when it happens 80-90% of the time doesn&#8217;t speak very well for the QA process at Microsoft. However, I can understand that the impact of this bug would have been deemed very insignificant as it impacts developers only and does not prevent them from doing their job. By the way, if you are also annoyed by the blank process dialog in the latest version of SQL Server, you will have to wait until the next release (2012) until you get a fix:</p>
<p><a href="http://connect.microsoft.com/SQLServer/feedback/details/536543/ssas-process-progress-window-blank-no-details">http://connect.microsoft.com/SQLServer/feedback/details/536543/ssas-process-progress-window-blank-no-details</a></p>
<p>The other bug is far more significant. It not only impair developers&#8217; ability to build some features, but is also highly visible to all Excel users. However, it is hard(er) to reproduce:</p>
<p><a href="http://connect.microsoft.com/SQLServer/feedback/details/484146/getting-an-error-when-trying-to-browse-a-cube">http://connect.microsoft.com/SQLServer/feedback/details/484146/getting-an-error-when-trying-to-browse-a-cube</a></p>
<p>Still, it seems like developers from {[World].[Countries].Members}-{[World].[Countries].[USA]} hit it all the time. I am speaking about the Locale Identifier bug. The most common occurrence is when drilling through to detail in Excel. After the drill-through action has been initiated, Excel shows a message box with a message talking about the XML Parser and how the Locale Identifier cannot be overwritten -</p>
<p><strong>&#8220;XML for Analysis parser: The LocaleIdentifier property is not overwritable and cannot be assigned a new value.&#8221;</strong></p>
<p>The cause is simple (as confirmed by the SSAS team at Microsoft and Akshai Mirchandani in particular): once we open a session we cannot overwrite the locale. The mystery is around the cause for Excel to do something like that. Noting that Excel is not the only offender, as I have also seen the same error message thrown by SQL Server Profiler, and <a href="http://cwebbbi.wordpress.com/">Chris Webb </a>has seen it with the Cube Browser in BIDS:</p>
<p><a href="http://connect.microsoft.com/SQLServer/feedback/details/484146/getting-an-error-when-trying-to-browse-a-cube">http://connect.microsoft.com/SQLServer/feedback/details/484146/getting-an-error-when-trying-to-browse-a-cube</a></p>
<p>Since the bug has been reported to Microsoft, we are now hopeful that a fix will appear at some point. Until then you can try the following workaround, courtesy of my friends and former colleagues Matthew Ward and Paul Hales:</p>
<p>- Switch the Windows Region and Language Format in Control Panel to English (United States):</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2012/01/region_language_format.png"><img class="size-full wp-image-473 alignnone" title="region_language_format" src="http://www.bp-msbi.com/wp-content/uploads/2012/01/region_language_format.png" alt="" width="477" height="550" /></a></p>
<p>- Switch it back to whatever it was before</p>
<p>Now the &#8220;bug&#8221; should be fixed for that machine. For example, I had my new Windows 7 workstation configured to use Australian formats. After I got the Locale Identifier error message in Profiler, I switched the formats to USA. The bug disappeared and I could profile SSAS. After that I switched Windows back to the original English (Australia) format&#8230;and nothing broke. I could still use Profiler and drill-through in Excel.</p>
<p>Another notice. <a href="http://www.artisconsulting.com/blogs/greggalloway/default.aspx">Greg Galloway </a>has released a new version (0.7.4) of the <a href="http://olappivottableextend.codeplex.com/releases/view/81169">OLAP Pivot Extensions add-in for Excel</a>. In case you have been experiencing a Locale Identifier problem in SSAS while using older versions of the add-in, please download the new one and let Greg know (e.g. on the <a href="http://olappivottableextend.codeplex.com/discussions">discussions page</a> on CodePlex) if the new release fies your problem.</p>
<p>Thanks to everyone involved in confirming and testing different fixes. Ideally, I would like to see Microsoft fixing this on the server side of things which would allow us to easily patch up all existing systems exhibiting the problem.</p>
<p>Since all Microsoft Connect item related to this bug have been closed, I opened a new one, so you can vote in order to prioritise this issue:</p>
<p><a href="https://connect.microsoft.com/SQLServer/feedback/details/721372/locale-identifier-bug" class="broken_link">https://connect.microsoft.com/SQLServer/feedback/details/721372/locale-identifier-bug</a></p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2012/01/ssas-locale-identifier-bug/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SSAS: Multiple SQL Queries in ROLAP Mode</title>
		<link>http://www.bp-msbi.com/2011/11/ssas-multiple-sql-queries-in-rolap-mode/</link>
		<comments>http://www.bp-msbi.com/2011/11/ssas-multiple-sql-queries-in-rolap-mode/#comments</comments>
		<pubDate>Sun, 27 Nov 2011 13:30:37 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[SSAS]]></category>
		<category><![CDATA[error]]></category>
		<category><![CDATA[referential integrity]]></category>
		<category><![CDATA[ROLAP]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=457</guid>
		<description><![CDATA[Just recently I was working on a project where I had to build a SSAS ROLAP cube on top of a badly built data mart. Badly built in this case meant one where we encounter multiple referential integrity (RI) issues. Most importantly, the designers ignored the very basic principle that all dimension keys for each [...]]]></description>
			<content:encoded><![CDATA[<p>Just recently I was working on a project where I had to build a SSAS ROLAP cube on top of a badly built data mart. Badly built in this case meant one where we encounter multiple referential integrity (RI) issues. Most importantly, the designers ignored the very basic principle that all dimension keys for each row must be present in the respective dimension tables. When in MOLAP mode, SSAS checks for such mismatches during processing. However, when a partition is in ROLAP storage mode, we don&#8217;t get a notification that anything is wrong and the cube processing operation succeeds. This situation has some consequences during execution time and I will try to illustrate those in this post and show a solution. Before I begin, I must say that if it wasn&#8217;t for Akshai Mirchandani&#8217;s (from the Microsoft SSAS dev team) and <a href="http://www.artisconsulting.com/blogs/greggalloway/default.aspx">Greg Galloway</a>&#8216;s help, I would have probably spent quite some time figuring out what is happening. Thanks to them the problem got solved quickly and I got to understand the reason for what is happening.</p>
<p>In terms of set-up, I created two tables in SQL Server: Dim and Fact. The Dim table contained two members A and B, with keys of 1 and 2. Initially, the Fact table had two rows referencing the Dim table &#8211; Dim keys of 1 and 2, and a measure column called Amount with 1.0 and 2.0 as the amounts corresponding to A and B. No issues here. After that I created a SSAS solution, corresponding to this simple dimensional model. I switched the partition storage for the cube to ROLAP and processed the SSAS database. After that I ran the following query, which I used for all subsequent examples:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/00_query.png"><img class="alignleft size-full wp-image-458" title="00_query" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/00_query.png" alt="" width="190" height="139" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>The result was as expected:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/04_good_ri_result.png"><img class="alignleft size-full wp-image-459" title="04_good_ri_result" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/04_good_ri_result.png" alt="" width="81" height="57" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>At the same time I had a SQL Server Profiler trace running, which showed:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/01_good_ri_trace.png"><img class="alignleft size-full wp-image-460" title="01_good_ri_trace" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/01_good_ri_trace.png" alt="" width="889" height="163" /></a></p>
<p>&nbsp;</p>
<p>We can see that SSAS has executed one SQL query retrieving data from the fact table. Nothing unusual thus far.</p>
<p>To spoil the party, I added one more row to the fact table with a dimension key of 3 and Amount of 3. Since I did not add a row in the dimension table with a key of 3, this broke the rules and if I had a foreign key constraint implemented between the fact and the dimension tables I would not have been able to do this. After cleaning the SSAS cache, I ran my query again. The result:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/03_bad_ri_result.png"><img class="alignleft size-full wp-image-461" title="03_bad_ri_result" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/03_bad_ri_result.png" alt="" width="79" height="58" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>The actual error was, of course, a missing key. I was not surprised when I saw this on my original project. However, looking at Profiler we see a &#8220;weird&#8221; sequence of events:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/02_bad_ri_trace.png"><img class="alignleft size-full wp-image-462" title="02_bad_ri_trace" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/02_bad_ri_trace.png" alt="" width="890" height="484" /></a></p>
<p>&nbsp;</p>
<p>SSAS runs multiple queries which result in errors. In this case we can see four of these ExecuteSQL events. All of them are followed by an error in a ReadData event. In this particular case we can see only four ExecuteSQL events. In the real-world, this scenario can get multiple times worse (in my case we saw 4667 queries run against the relational database in a few minutes) leading to a really significant drop in performance.</p>
<p>So, what is happening? According to Akshai, SSAS encounters an error while dealing with the results from the initial SQL query and is trying to recover by sending more queries. In some cases this can result in getting the error in the result set only for some cells.</p>
<p>Luckily, there is an easy way out of this situation (thanks to Greg for providing the tips). SSAS can automatically create an &#8220;unknown bucket&#8221; for each dimension and can assign to it all measure values which do not correspond to a dimension member. To get this result, we must ensure that each affected partition&#8217;s error configuration is set to something similar to:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/05_default_partition_error_config.png"><img class="alignleft size-full wp-image-463" title="05_default_partition_error_config" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/05_default_partition_error_config.png" alt="" width="378" height="278" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Note that the KeyErrorAction is ConvertToUnknown, not DiscardRecord (which is the alternative). This must also be coupled with setting up each &#8220;incomplete&#8221; dimension to include an Unknown member:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/07_dim_with_unknown.png"><img class="alignleft size-full wp-image-464" title="07_dim_with_unknown" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/07_dim_with_unknown.png" alt="" width="383" height="308" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>It does not matter whether the UnknownMember is Visible or Hidden, as long as it is not None.</p>
<p>Back to our scenario. After setting these properties on the dimension and the partition I processed the SSAS database again and executed the query. The result:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/09_result_with_unknown.png"><img class="alignleft size-full wp-image-465" title="09_result_with_unknown" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/09_result_with_unknown.png" alt="" width="182" height="79" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>and the profiler trace:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/08_trace_with_unknown.png"><img class="alignleft size-full wp-image-466" title="08_trace_with_unknown" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/08_trace_with_unknown.png" alt="" width="933" height="166" /></a></p>
<p>&nbsp;</p>
<p>As we can see we eliminated the multiple queries. If we do not want to see the Unknown amount in the cube we can use a scope assignment:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/10_scope.png"><img class="alignleft size-full wp-image-467" title="10_scope" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/10_scope.png" alt="" width="270" height="51" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Coupled with making the UnknownMember Hidden, we can completely obliterate traces of our underlying RI issues. Unless our users check the numbers, but then we can blame whoever designed the datamart! :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2011/11/ssas-multiple-sql-queries-in-rolap-mode/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Alternate Ordering of Attributes in SSAS</title>
		<link>http://www.bp-msbi.com/2011/11/alternate-ordering-of-attributes-in-ssas/</link>
		<comments>http://www.bp-msbi.com/2011/11/alternate-ordering-of-attributes-in-ssas/#comments</comments>
		<pubDate>Sat, 05 Nov 2011 11:30:38 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[SSAS]]></category>
		<category><![CDATA[dimension]]></category>
		<category><![CDATA[ordering]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=445</guid>
		<description><![CDATA[Sometimes we need to display attribute members in SSAS in a different order than the order of its name or key. For this purpose we have the option to use one of its attribute&#8217;s name or key. However, in some cases changing the order may break some calculation logic which depends on the initial order. [...]]]></description>
			<content:encoded><![CDATA[<p>Sometimes we need to display attribute members in SSAS in a different order than the order of its name or key. For this purpose we have the option to use one of its attribute&#8217;s name or key. However, in some cases changing the order may break some calculation logic which depends on the initial order. The new ordering may also be inconvenient for writing MDX as using some functions of the language is easier (at least conceptually) when thinking of sets in ascending order. The best example which we can use to illustrate this problem is the Date dimension. While in most, if not all, cases the Date dimension is ordered in ascending order, sometimes users prefer to see the most recent date first and request us to change the order to descending. Doing so invalidates many time intelligence calculations like rolling and parallel periods, etc. Furthermore, fixing those requires inverting numbers to negative, or avoiding the use of functions like ClosingPeriod. All in all, a &#8220;small&#8221; change can lead to a big problem. We can, however, accommodate our ignorant users (which unknowingly get the benefit of <a href="http://jsimonbi.wordpress.com/2011/11/19/date-order/">reading default time series charts backwards</a> – from right to left – when dragging-dropping descending dates in Excel, for example) without changing too much in our scripts. A little trick in the modelling can help and it is the reason for writing this post.</p>
<p>Let&#8217;s have a look at a simple Date dimension with one attribute – Date. Nothing unusual, with the Date being ordered by its Key (integer in this case) and with a name coming from another column in the Date table – DateName. When we create a simple slice in Excel we get the following:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/alt-order-01.png"><img class="alignleft size-full wp-image-446" title="alt-order-01" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/alt-order-01.png" alt="" width="169" height="241" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Now we create a measure Rolling 3 Days Amount, which sums the last 3 days&#8217; amount:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/alt-order-02.png"><img class="alignleft size-full wp-image-447" title="alt-order-02" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/alt-order-02.png" alt="" width="314" height="238" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>The MDX for this calculation is:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/alt-order-03.png"><img class="alignleft size-full wp-image-448" title="alt-order-03" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/alt-order-03.png" alt="" width="512" height="101" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>If we simply invert the order of the Date attribute by ordering it by another column in our Date table, which contains DateKey*-1 and refresh the Excel pivot table we get the following:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/alt-order-04.png"><img class="alignleft size-full wp-image-449" title="alt-order-04" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/alt-order-04.png" alt="" width="316" height="221" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>This is simply incorrect. A relatively small change in the MDX script can help us with this issue (e.g. changing the Lag to Lead), however in many cases we do not want to rebuild all the measures. Luckily, we can employ a different tactic. Instead of changing the script, we can change the structure of our dimension by adding an additional attribute which is not exposed to the users. (i.e. is hidden). This attribute will be based on the same column we use for our Date, but will not be ordered by the descending column. We can rename the original attribute (the one exposed to the users) to something like Date Desc, or a more user-friendly option, and hide the new one:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/alt-order-05.png"><img class="alignleft size-full wp-image-450" title="alt-order-05" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/alt-order-05.png" alt="" width="153" height="69" /></a>         <a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/alt-order-06.png"><img class="alignleft size-full wp-image-451" title="alt-order-06" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/alt-order-06.png" alt="" width="160" height="71" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Everything else stays the same – our cube script does not need to be adjusted and its logic is correct:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/11/alt-order-07.png"><img class="alignleft size-full wp-image-452" title="alt-order-07" src="http://www.bp-msbi.com/wp-content/uploads/2011/11/alt-order-07.png" alt="" width="314" height="240" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>A different approach could be to leave the old attribute named Date, so there is no change necessary in case of reports depending on the naming. This, however, requires a change of the cube script, which can be easily performed with using the BIDS Replace functionality (e.g. Ctrl+H).</p>
<p>Note that for this approach to work we need to make sure that the attribute exposed to the users is the dimension key attribute as changing its current member results in an (infamous) attribute overwrite where its related attributes, which are above it in the relationship chain) also change. If we expose the non-key date attribute our MDX logic will break as the changes to its current member will not affect the attributes below it (actually, it will set them to their All member).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2011/11/alternate-ordering-of-attributes-in-ssas/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building a Date Table</title>
		<link>http://www.bp-msbi.com/2011/09/building-a-date-table/</link>
		<comments>http://www.bp-msbi.com/2011/09/building-a-date-table/#comments</comments>
		<pubDate>Mon, 19 Sep 2011 10:52:09 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[PowerPivot]]></category>
		<category><![CDATA[SSAS]]></category>
		<category><![CDATA[dates]]></category>
		<category><![CDATA[dimensions]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=429</guid>
		<description><![CDATA[Date tables in themselves are nothing new. Every data warehouse and business intelligence project includes one of those and typically it is one of the first tables which we find on our list of implementation tasks. Surprisingly, however, I am finding that in many implementations the omnipresent date table cannot support some analytics. In this [...]]]></description>
			<content:encoded><![CDATA[<p>Date tables in themselves are nothing new. Every data warehouse and business intelligence project includes one of those and typically it is one of the first tables which we find on our list of implementation tasks. Surprisingly, however, I am finding that in many implementations the omnipresent date table cannot support some analytics. In this post I will outline a few considerations which we need to take into account when building date tables in general, and some which apply specifically to SSAS.</p>
<p><span style="color: #ff0000;">UPDATE (9th October 2011):</span> If you are a <span style="color: #008000;"><strong>PowerPivot</strong></span> user (or would not mind using an OData feed) there is a simple way to get a date/calendar table as there is a free one available on the Azure DataMarket. I recently blogged about this new project in my <a href="http://www.bp-msbi.com/2011/10/introducing-project-datestream-codeplex/">Introducing Project DateStream (CodePlex)</a> post.</p>
<p><span style="color: #ff0000;">UPDATE 2 (16 October 2011):</span> John Simon recently published a nice <a href="http://jsimonbi.wordpress.com/2011/10/09/populating-your-date-dimension/">T-SQL script which can be used to create and populate  a date table </a>on his blog. Have a look if you need one!</p>
<h5>Grain, Key and Format</h5>
<p>In general, date tables are on a daily/date grain. This is because the lowest level of reporting we need to do is very often on full days. Even if we need to analyse on time intervals smaller than a day, we should still build a Date and a Time table to support this. Why? Because if we pack it all in the same table we end up with too many rows and this is something we typically want to avoid in any dimension. As we have a row per day, one of our columns is inevitably based on the calendar date. It is also typically the dimension key. As with all other dimension tables, we need to be able to join the table to our fact tables and this is done on our key. To keep our fact tables as small as possible, we need the smallest possible data type for our keys, and in the case of a Date this is usually an integer. However, unlike with other dimensions, we do not have to have a meaningless integer for our surrogate key because it does not give us any advantage. It is very easy to convert between a datetime and an int and in SQL Server datetime is 8 bytes, while int is 4. In SQL 2008+ we have another type suitable for our date table key – date, which is 3 bytes. However, for compatibility reasons, it is frequently better to stick to an int. Luckily, we also have the very convenient ANSI/<a href="http://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a> standard to follow in order to make our integer dates easier to work with. If we do encode them with the YYYYMMDD format, (thus the 15<sup>th</sup> of January 2011 becomes 20110115), we can easily sort on the column and compare two dates with the standard &gt; and &lt; operators. Additionally, we also escape the ambiguities around date formats in the USA and the rest of the world.</p>
<h5>Attributes</h5>
<p>Building the date key column is a good start but to allow for better analytical capabilities we need to add other attributes. As in most cases we need to analyse our data not only on days, but also on larger intervals (e.g. Months, Quarters and Years), we need to add columns for each of them. A typical requirement is to support both Financial and Calendar date hierarchies. As with dimensions it is ok to have many columns, we can add one for each combination of the type of calendar and period (e.g. FinancialMonth and CalendarMonth, FinancialQuarter and CalendarQuarter, etc.). Other interesting attributes we may want to have materialised in the table are the likes of Weekends, Public Holidays (even though we need to maintain these), Solstice/Equinox and PhaseOfMoon (thanks for<a href="http://blog.kejser.org/"> Thomas Kejser </a>for mentioning these in an online conversation recently). Basically, for a fully functional date table we need to consider anything which could be of business value without going to extremes.</p>
<p>Of course, when working with SSAS we also want to have an integer key for each attribute and possibly a common name for it. This multiplies the number of columns we need by two – one Id and one Name column for each of the attributes we have decided to implement. Some attention needs to be spared when determining the formats of each attribute Id. If we are to be building a hierarchy out of a collection of attributes we want those to form a nice natural hierarchy. That is – each child member should not have two parents with different Ids. To illustrate the concept, let&#8217;s consider two different months – January 2011 and January 2012. While they are the first month of the calendar year, they represent different entities when reporting. We do not aggregate data to January only, but to January in each respective year. Therefore, if we were to write a SQL query to get data for January 2011 and our Ids for both of these members are 1, we would also need to use the Year attribute to get the values we need. Effectively, our hierarchy would have two children with identical Ids of 1 with different parents (with Ids of 2011 and 2012). This is a particular problem when working with SSAS as it definitely prefers unique Ids for each separate attribute member. There is a very easy solution – we can include both the Year and the Month number in the MonthId. In our case, January 2011 gets an Id of 201101 and January 2012 – 201201. Now we don&#8217;t have the same issue. Similarly, we must pay attention when we construct the Ids of other attributes which participate in our hierarchies like Quarter (YYYYQQ) and Half Year (YYYYHH).</p>
<h5>Weeks</h5>
<p>The week is a special case in the calendar. While we can say that Days roll up to Months, which roll up to Quarters, which in turn roll up to Half Years and Years, Weeks are a different story. If we are not using a special calendar like a 4-4-5 calendar, we are dealing with a real-world entity, which does not naturally belong to only one larger period. In most cases we do not have to worry about the week falling between Day and Month as business understands that this is not a very easy to work with hierarchy. However, business users very often are ignorant about the fact that weeks do not roll up nicely to years, too. We can again read ISO 8601, which <a href="http://en.wikipedia.org/wiki/ISO_week_date">also deals </a>with the Week-&gt;Year problem. Basically, the ISO has come up with a simple solution – if we have a week which has dates in two years, we count it towards the year which contains more dates (or, the year which contains the Thursday of the week). Why is this important? Well, we can simply split a week in two, however, this means that certain weeks in our table contain less than 7 days. If we compare such weeks with a Weekly Growth calculation we will notice a problem – the amounts aggregated to them are smaller than usual. Similarly, on a graph showing weekly amounts, we have a dip as the two parts of the same week are plotted as separate points. If the users do not care, then it is not a problem, but it is something we should consider and ask about when building the week attribute in our date table.</p>
<h5>Ranges</h5>
<p>The date table has a limited amount of rows and we have to make a decision on how many are enough. Some developers build date tables with ranges all the way from 1900 to 2100, or even further. As we have <a href="http://en.wikipedia.org/wiki/Leap_year#Gregorian_calendar">roughly 365.25 days per year </a>(note how 1900 is not a leap year, not is 2100 – something Excel doesn&#8217;t know), for 10 years of data we end up with ~3652 rows. With 100 years we have 36525 rows. It is quite doubtful that a data warehouse will contain data for all these years. In most cases it contains a bit of historical data and is designed to keep data for another 20-50 years. To optimise the performance of the queries using the date table it is a good idea to have a dynamic range of dates. In our ETL we can easily keep expanding the range as needed, or collapse it if we ever purge fact data. One thing which is often overlooked when picking the date range is the fact that many times queries depend on the completeness of the date range. A major mistake, which we must avoid are basing the date table on fact data and allowing gaps in the range, and having incomplete top-level periods.</p>
<p>The first problem is easy to explain. Zealously trying to keep the date dimension as small as possible by reducing the number of days (i.e. rows) to only the applicable ones for our fact data can introduce gaps in the overall table. In example, if we have no data for 26<sup>th</sup> of January because our business was closed for<a href="http://en.wikipedia.org/wiki/Australia_Day"> Australia Day</a>, and we &#8220;optimise&#8221; the date table to exclude this day from the date table, all analytics which depend on counting the number of dates in January will be skewed. An average calculation doing Sales/NumberOfDaysPerMonth will divide by 30, not 31. One of the reasons for having a date table at the first place is to avoid such problems. Hence, gaps in the date table must be avoided.</p>
<p>Secondly, we must also ensure that all top-level periods (i.e. Year usually is the top level in the Calendar Hierarchy) must be also complete. It is not acceptable to cut off the date range with a month, so we have a constant number of dates. Even if our fact data is implemented over a fixed window of 24 months (rolling), we should not do the same with the date table. In example, if we are in September 2011 and we have fact data for 24 months prior to this (e.g. September 2009 – September 2011), the date table should also include data for months prior to that (e.g. January 2009 – September 2011). The reason is the same as before – all calculations doing Amount/NumberOfPeriodsWithinAPeriod would be wrong for 2009. Furthermore, if we use something like window functions in SQL partitioning by year and counting the months within the period to compare equivalent ones will be incorrect. The first month of 2009 would be September and the first in 2010 – January. Because of such issues, it is best to keep all top level periods complete. A solution could be removing data from the date table once we are not interested in the complete top level period. In the case of the 24 rolling months, we can remove all of 2009 with all its periods/rows once we move to 2012 and we are interested in January 2010 – January 2012.</p>
<p>In SSAS all date functions like ParallelPeriod and ClosingPeriod work with relative periods. To get the ParallelPeriod for January 2010 in 2009, SSAS will determine that January 2010 is the first month in 2010, go back to 2009 and pick the first month there. If the first month is September 2009, we will get that returned.</p>
<h5>Unknowns</h5>
<p>As with other dimensions, we should also have an Unknown member in the date dimension. While with all other dimensions we usually pick a value like -1 for the Unknown member Id and Name of &#8220;Unknown&#8221;, with a date table things a slightly different as we often have columns which are some sort of a date/time data type and we cannot cast -1 to a date in a meaningful way. Therefore, in many cases we can pick a complete outlier, like 19000101, which we use for storing Unknowns. Depending on the scenario, we may not need to do that, but if we do, there is nothing wrong with doing that as long as we make sure that it is clear that it is a special case. If the data starts in 2001 and we pick 20000101 as an unknown value many users will be wondering why there is some data against that date.</p>
<h5>Conclusion</h5>
<p>The best date table is the one we don&#8217;t notice and take for granted. Given that it is not something that changes at all, the structure of the date table is the one common over many different implementations and whether in SQL Server, SSAS or PowerPivot, the fundamentals stay the same. It can be shared and is part of the base of virtually every BI solution. It, unfortunately, is built wrong very often, thus severely impairing the capability of the system it is a part of. With the arrival of self-service BI I could imagine an increasing need for practical advice on this specific data modelling technique and I hope this article helps with delivering a bit of it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2011/09/building-a-date-table/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SSAS Myths Dispelled</title>
		<link>http://www.bp-msbi.com/2011/07/ssas-myths-dispelled/</link>
		<comments>http://www.bp-msbi.com/2011/07/ssas-myths-dispelled/#comments</comments>
		<pubDate>Fri, 22 Jul 2011 07:09:22 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[SSAS]]></category>
		<category><![CDATA[myths]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=421</guid>
		<description><![CDATA[This post is an attempt to dispel a few myths which seems to get repeated over and over among SSAS developers. While the truths are nothing new and have been documented in multiple sources like BOL, SQL CAT whitepapers, books and blog posts, they seem to consistently escape the attention of the wider public. 1 [...]]]></description>
			<content:encoded><![CDATA[<p>This post is an attempt to dispel a few myths which seems to get repeated over and over among SSAS developers. While the truths are nothing new and have been documented in multiple sources like BOL, SQL CAT whitepapers, books and blog posts, they seem to consistently escape the attention of the wider public.</p>
<h6>1 SSAS pre-aggregates data <span style="color: #993300;"><strong>by default</strong></span></h6>
<p>While it is true that SSAS can pre-aggregate data this does not happen by default. SSAS compresses data, indexes data and caches data but it does not pre-aggregate data unless we define aggregations. When I am saying pre-aggregate I mean that SSAS does not automatically know what the Internet Sales Amount for Australia in 2007 is. It needs to get the leaf-level data and sum it up; unless we have built an aggregation on Country and Year for the partition containing the Internet Sales Amount measure. In that case the data is pre-aggregated and ready for retrieval.</p>
<h6>2 We can emulate in MDX <span style="color: #993300;"><strong>at no cost</strong></span> Enterprise Edition functionality in Standard Edition</h6>
<p>Well, we can’t. We can emulate certain features like LastNonEmpty aggregation functions for example, but it comes at a cost. The cost usually relates to Storage Engine (multi-threaded) vs Formula Engine (single-threaded) execution.</p>
<h6>3 SSAS is <span style="color: #993300;"><strong>always</strong></span> faster than SQL Server RDBMS</h6>
<p>While it is true that SSAS is faster than SQL Server RDBMS in many cases, this does not always hold true. A particular area in which the relational engine beats SSAS is the retrieval and processing of low-level granular data. SSAS usually beats the RDBMS when it comes to ad-hoc access to aggregated data.</p>
<h6>4 MOLAP is <span style="color: #993300;"><strong>always</strong></span> faster than ROLAP</h6>
<p>If you read SQL CAT’s “<em>Analysis Services ROLAP for SQL Server Data Warehouses</em>” whitepaper you can see that after careful tuning ROLAP can be faster than MOLAP. Not always, but sometimes – enough to claim that it is not true that MOLAP is <strong>always</strong> faster than ROLAP. This ties a bit to the previous myth and proves that a well tuned RDBMS can perform very well with aggregates.</p>
<p>From the paper:</p>
<blockquote><p><em>“At last, SQLCAT’s redesign and optimization efforts paid off. The ROLAP cube was finally ready for performance testing, and thanks to the amazingly fast performance of the relational SQL Server engine on top of a super-fast storage subsystem, the results looked better than expected. To everybody’s surprise, the ROLAP cube outpaced the MOLAP cube in 45 percent of all queries right from the start (see Figure 14). Only 39 percent of the queries showed substantially slower response times in ROLAP mode (more than twice the amount of MOLAP time) and 16 percent showed moderate performance degradation (less than twice the amount of MOLAP time).”</em></p></blockquote>
<h6>5 Usage Based Optimisations do <span style="color: #993300;"><strong>not</strong></span> work well</h6>
<p>In SQL Server Analysis Services 2008 the Usage Based Optimisation (UBO) algorithm has been redesigned. Now it works, and it works well. It does not create redundant aggregations and in general performs much better. Building UBO aggregations has always been recommended by Microsoft and even more so now.</p>
<h6>6 Rigid attribute relationships <span style="color: #993300;"><strong>boost performance</strong></span></h6>
<p>Whether an attribute relationship is Rigid or Flexible does not actually improve performance at all. Not query performance. A wrong choice here only affects processing of partition indexes. If an attribute relationship is static, setting it to Rigid means that you do not have to process partition indexes when you update the dimension. This is all the benefit you get from Rigid relationships. Going too far and marking changing relationships to Rigid may have a very negative impact as a change will prompt a complete process of the partition data and indexes, which will take much longer than updating just the indexes. Either way, there is no difference during query execution.</p>
<h6>7 MDX and DAX are <span style="color: #993300;"><strong>hard</strong></span></h6>
<p>I believe that this particular myth stems from the fact that we get to compare MDX and DAX to sweet and fluffy languages like SQL and C#. It all depends on the vantage point. Take the following “Hello world!” program in <strong><a href="http://en.wikipedia.org/wiki/Malbolge#.22Hello_world.22_in_Malbolge">Malbolge</a> </strong>for comparison purposes:</p>
<p><span style="color: #800000;">(&#8216;&amp;%:9]!~}|z2Vxwv-,POqponl$Hjig%eB@@&gt;}=&lt;M:9wv6WsU2T|nm-,jcL(I&amp;%$#&#8221;</span><br />
<span style="color: #800000;"> `CB]V?Tx&lt;uVtT`Rpo3NlF.Jh++FdbCBA@?]!~|4XzyTT43Qsqq(Lnmkj&#8221;Fhg${z@&gt;</span></p>
<p>MDX is not all that bad from a Malbolge developer’s point of view, is it?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2011/07/ssas-myths-dispelled/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Custom Groups in Excel 2007 &#8211; Error</title>
		<link>http://www.bp-msbi.com/2011/07/custom-groups-in-excel-2007-error/</link>
		<comments>http://www.bp-msbi.com/2011/07/custom-groups-in-excel-2007-error/#comments</comments>
		<pubDate>Mon, 11 Jul 2011 00:35:06 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[SSAS]]></category>
		<category><![CDATA[custom groups]]></category>
		<category><![CDATA[error]]></category>
		<category><![CDATA[Excel]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=416</guid>
		<description><![CDATA[I just finished digging around a particular issue with Excel 2007 (some versions) and SSAS Pivot Tables. In brief, the issue was that a user could not use the custom groups functionality which Excel provides because she got an error saying: &#8220;The query did not run, or the database table could not be opened. Check [...]]]></description>
			<content:encoded><![CDATA[<p>I just finished digging around a particular issue with Excel 2007 (some versions) and SSAS Pivot Tables. In brief, the issue was that a user could not use the custom groups functionality which Excel provides because she got an error saying:
</p>
<blockquote><p>&#8220;The query did not run, or the database table could not be opened. Check the database server or contact your administrator. Make sure the external database is available and hasn&#8217;t been moved or reorganized, then try the operation again.&#8221;</p></blockquote>
<p>I added her to the server administrators, but the message persisted. After profiling I noticed that the MDX generated by Excel 2007 for this operation read:
</p>
<blockquote>
<div>CREATE SESSION CUBE [Cube_XL_GROUPING0] FROM [Cube] <span style="color: #ff0000;"><strong>( DIMENSION</strong></span> [Cube].[Agency].[Agency Hierarchy] HIDDEN AS _XL_GROUPING0,DIMENSION [Cube].[Agency].[Flag],DIMENSION [Cube].[Agency].[Region],DIMENSION [Cube].[Collection].[Application],DIMENSION [Cube].[Collection].[Application Code],DIMENSION [Cube].[Collection].[Data Collection Code],DIMENSION [Cube].[Data...</div>
<div><span style="color: #993300;"><em><strong></p>
<p>Error: "Parser: The syntax for 'DIMENSION' is incorrect."</strong></em></span></div>
<div></div>
</blockquote>
<div>I have highlighted the problematic part - the MEASURE part of this expression was missing. A correct MDX statement issued by another instance of Excel 2007 running on a different machine showed:</div>
</p>
<blockquote>
<div><span style="color: #008000;">CREATE SESSION CUBE [Cube_XL_GROUPING1] FROM [Cube] ( MEASURE [Cube].[Value - Data Integer Quarter] HIDDEN,MEASURE [Cube].[Value - Data Integer Semi] HIDDEN,MEASURE [Cube].[Value - Data Integer Annual] HIDDEN,MEASURE [Cube].[Value - Data Integer Month] HIDDEN,MEASURE [Cube].[Value - Data Real Quarter] HIDDEN,MEASURE [Cube].[Value - Data Real Month] HIDDEN,MEASURE [Cube].[Value - Data Real Annual] HIDDEN,MEASURE [Cube].[Value - Data Money Semi] HIDDEN,MEASURE [Cube].[Value - Data Money Month] HIDDEN,MEASURE [Cube].[Value - Data Real Semi] HIDDEN,MEASURE [Cube].[Value - Data Money Quarter] HIDDEN,MEASURE [Cube].[Value - Data Money Annual] HIDDEN,DIMENSION</span> [Cube].[Agency].[Agency Hierarchy] HIDDEN AS _XL_GROUPING0,DIMENSION [Cube].[Agency].[Pub Pte Flag],DIMENSION [Cube].[Agency].[Region],DIMENSION [Cube].[Collection].[Application],DIMENSION [Cube].[Collection].[Application Code],DIMENSION [Cube].[Collection].[Collection Code],DIMENSION [Cube].[Element].[Common Name],DIMENSION [Cube].[Element].[Data Element Code],DIME&#8230;</div>
</blockquote>
<div>Here we have the cube measures as a part of the CREATE SESSION CUBE statement and this makes it a valid one. The reason for this seems to be the fact that all the physical measures in the cube were hidden and only one calculated measure was shown to the users. Excel (2007 Enterprise) seemed unable to find them, so the fix was easy &#8211; creating a visible dummy physical measure and using a scope assignment to make it work like the calculated one. Now Excel merrily creates valid MDX and my user is happy.</div>
</p>
<div>I understand this will be a very rare problem, but it takes some time to investigate, so I hope the post may help someone out there.</div></p>
]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2011/07/custom-groups-in-excel-2007-error/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MDX Subselects &#8211; Some Insight</title>
		<link>http://www.bp-msbi.com/2011/07/mdx-subselects-some-insight/</link>
		<comments>http://www.bp-msbi.com/2011/07/mdx-subselects-some-insight/#comments</comments>
		<pubDate>Tue, 05 Jul 2011 06:53:21 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[SSAS]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[subselects]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=409</guid>
		<description><![CDATA[Recently I answered a question on StackOverflow, which may be an interesting, common case and understanding it correctly helps understanding subselects better. Let’s examine the following MDX query: Here we effective place the All member of the Customer.Education hierarchy on columns, and an ordered set of the countries in the Customer dimension on rows. We [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I answered <a href="http://stackoverflow.com/questions/6527938/why-does-order-ignore-subselect">a question on StackOverflow</a>, which may be an interesting, common case and understanding it correctly helps understanding subselects better.</p>
<p>Let’s examine the following MDX query:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/07/subselects_first_query.png"><img class="alignnone size-full wp-image-411" title="subselects_first_query" src="http://www.bp-msbi.com/wp-content/uploads/2011/07/subselects_first_query.png" alt="" width="588" height="459" /></a></p>
<p>Here we effective place the All member of the Customer.Education hierarchy on columns, and an ordered set of the countries in the Customer dimension on rows. We have a subselect and a slicer. The slicer contains the Internet Order Count measure (which places is it in context) and the slicer restricts the query to look at customers with Partial High School education only.</p>
<p>When we execute the query we get exactly what we expect.</p>
<p>Now, let’s change this to:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/07/subselects_second_query.png"><img class="alignnone size-full wp-image-413" title="subselects_second_query" src="http://www.bp-msbi.com/wp-content/uploads/2011/07/subselects_second_query.png" alt="" width="606" height="383" /></a></p>
<p>The difference here is the All member in the tuple used as a second argument of the Order function. What we get is a different order (note that Germany and France are on different positions on rows). It seems like the set is ordered by the total amount for all customers without taking their education in consideration – the subselect does not make a difference. However, the measure value is the same as in the first query. So, what causes this?</p>
<p>To answer, we need first to understand what a subselect does. As <a href="http://sqlblog.com/blogs/mosha/archive/2008/11/04/as2008-mdx-subselects-and-create-subcube-in-non-visual-mode.aspx">Mosha posted a while ago</a>, a subselect (which is really the same as a subcube) does <strong>implicit exists</strong> with the sets or set expressions on each axis and also applies <strong>visual totals “even within expressions if there are no coordinate overwrites”</strong>.</p>
<p>Instead of explaining the same as what Mosha has already spent the effort to explain, I will advise you <a href="http://sqlblog.com/blogs/mosha/archive/2006/11/12/slicer-and-axis-interaction-in-mdx-part-2-implicit-exists.aspx">to read this post thoroughly</a>. Then, you would understand what the “implicit exists” does. In our case, it is not as important as the visual totals part, so I will concentrate on it.</p>
<p>The reason why the set gets ordered by orders made by customers with partial high school education is the visual totals. It takes place within the Order expression. The visual totals also restrict what we see in the query results, as it applies to the slicer axis measure, as well. However, in this case the catch is in the <strong>“if there are no coordinate overwrites”</strong> part of the story. The visual totals in Order does not get applied because we explicitly overwrite the Customer.Education hierarchy member within the tuple in the Order function:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/07/subselects_order_expression.png"><img class="alignnone size-full wp-image-414" title="subselects_order_expression" src="http://www.bp-msbi.com/wp-content/uploads/2011/07/subselects_order_expression.png" alt="" width="421" height="95" /></a></p>
<p>Therefore, the set of countries gets ordered by the Internet Order Count for All Customers without taking into account the subselect. However, the measure on the slicer axis still gets the visual total logic applied to it, and this causes the result set to be for those customers who have Partial High School education.<br />
If we re-write the second statement to:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/07/subselects_third_query.png"><img class="alignnone size-full wp-image-410" title="subselects_third_query" src="http://www.bp-msbi.com/wp-content/uploads/2011/07/subselects_third_query.png" alt="" width="606" height="384" /></a></p>
<p>We can see that the <strong>NON VISUAL</strong> keyword (SSMS can&#8217;t recognise this syntax and underlines with a red squiggly line) changes the way the measure is displayed. We see the total amount for the slicer, as well.</p>
<p>Similarly, if we re-write the first query with NON VISUAL we get:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/07/subselects_fourth_query.png"><img class="alignnone size-full wp-image-412" title="subselects_fourth_query" src="http://www.bp-msbi.com/wp-content/uploads/2011/07/subselects_fourth_query.png" alt="" width="584" height="451" /></a></p>
<p>Here both visual totals are excluded and both the Order and the result set are done for customers with any education.</p>
<p>Hopefully this will clarify the logic applied when we use subselects to some extent.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2011/07/mdx-subselects-some-insight/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Colour Codes in SSAS</title>
		<link>http://www.bp-msbi.com/2011/06/colour-codes-in-ssas/</link>
		<comments>http://www.bp-msbi.com/2011/06/colour-codes-in-ssas/#comments</comments>
		<pubDate>Thu, 30 Jun 2011 02:49:28 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[SSAS]]></category>
		<category><![CDATA[colours]]></category>
		<category><![CDATA[measure formatting]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=406</guid>
		<description><![CDATA[When we apply colour formatting to measures in SSAS we get a &#8220;strange&#8221; colour code for our expressions from the BIDS colour-picker. For example, if we want to colour a certain measure in Red, we can write: CREATE MEMBER CURRENTCUBE.[Measures].[Red Measure] AS This = 1, FORE_COLOR=255; If we use the colour picker we can get [...]]]></description>
			<content:encoded><![CDATA[<p>When we apply <a href="http://www.bidn.com/blogs/DevinKnight/ssis/526/using-ssas-mdx-calculation-color-expressions">colour formatting to measures in SSAS</a> we get a &#8220;strange&#8221; colour code for our expressions from the BIDS colour-picker. For example, if we want to colour a certain measure in <span style="color: #ff0000;">Red</span>, we can write:</p>
<blockquote><p>CREATE MEMBER CURRENTCUBE.[Measures].[Red Measure] AS<br />
This = 1,<br />
FORE_COLOR=255;</p></blockquote>
<p>If we use the colour picker we can get more complex numbers for more complex colours. If we want to apply the <strong><span style="color: #8080c0;">colour </span></strong>with <span style="color: #ff0000;">R</span><span style="color: #00ff00;">G</span><span style="color: #0000ff;">B</span> of  (128,128,192), the colour picker generates the code 12615808 for use in the FORE_COLOR function.</p>
<p>Constructing our own color code is not all that hard. In fact, all we have to do is the following:</p>
<p>1. Multiply the Blue decimal code by 65536 (which is 2^16)<br />
2. Multiply the Green decimal code by 256 (yes, 2^8)<br />
3. Add the numbers from step 1 and 2 and the decimal code for Red</p>
<p>In other words, we can use the following formula:</p>
<p>c = r + 256*g + 65536*b</p>
<p>Where c is the colour code we need and r,g,b are the decimal codes (between 0 and 255) for each colour channel.</p>
<p>If we apply this to our (128,128,192) colour, we get:</p>
<p>c = 128 + 256*128 + 65536*192 = 128 + 32768 + 12582912 = 12615808</p>
<p>And this is exactly what we get from the colour picker control in BIDS.</p>
<p>As Chris Webb points out in the comments section below, we can also write FORE_COLOR=RGB(128,128,192) instead of calculating the colour code manually, which is way more practical. :)</p>
<p>I wish such little bits and pieces are better documented on MSDN as the current page in regards to the BACK_COLOR and FORE_COLOR properties is fairly basic: <a href="http://msdn.microsoft.com/en-us/library/ms145991.aspx"><span>http://msdn.microsoft.com/en-us/library/ms145991.<span>aspx</span></span></a>.</p>
<p><span style="color: #800000;"><strong>UPDATE (01/07/2011):</strong></span></p>
<p>Considering that RGB() is a VBA function, I tested the performance we get from using it. I have a simple measure, which I am formatting with an IIF expression. I tested three scenarios &#8211; with no FORE_COLOR formatting, with FORE_COLOR and numeric codes, and FORE_COLOR with RGB function. Each query was run 3 times on warm cache and returned a result set of  500,000+ cells. The results were as follows:</p>
<p>No FORE_COLOR: 2.3 seconds</p>
<p>FORE_COLOR=12615808: 5.3 seconds</p>
<p>FORE_COLOR=RGB(128,128,192): 17.7 seconds</p>
<p>In other words, applying a VBA function for colour formatting <span style="text-decoration: underline;">severely impacts the performance</span> of our queries. Thus, if you really need to format the colour of your measures, you may be better off doing it the hard way by converting the RGB values to the colour codes the same way the colour-picker control does in BIDS.</p>
<p><span style="color: #800000;"><strong>UPDATE2 (04/07/2011):</strong></span></p>
<p><span><span>As Valentino <span>Vranken</span> commented below, you can also use hex codes for the colours. However, there is a small twist. The codes need to be in <span style="color: #0000ff;">B</span><span style="color: #00ff00;">G</span><span style="color: #ff0000;">R</span>, not in <span style="color: #ff0000;">R</span><span style="color: #00ff00;">G</span><span style="color: #0000ff;">B</span> format. So, <span style="color: #ff0000;">Red</span> becomes 0000FF. The actual format of the hex expression is FORE_COLOR=&#8221;&amp;<span>Hxxxxxx</span>&#8220;. For <span style="color: #ff0000;">Red</span> we can use FORE_COLOR=&#8221;&amp;H0000FF&#8221;. There is no performance difference between hex and decimal codes, so it is up to your preference whether you go with one or the other. Converting 0000FF to decimal also shows the same decimal number (255) as performing the math above and if you already know the <span style="color: #0000ff;">B</span><span style="color: #00ff00;">G</span><span style="color: #ff0000;">R</span> hex you can simply convert it to a decimal.</span></span></p>
]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2011/06/colour-codes-in-ssas/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Database Compression Effects on SSAS Processing</title>
		<link>http://www.bp-msbi.com/2011/06/database-compression-effects-on-ssas-processing/</link>
		<comments>http://www.bp-msbi.com/2011/06/database-compression-effects-on-ssas-processing/#comments</comments>
		<pubDate>Wed, 22 Jun 2011 05:39:49 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[SSAS]]></category>
		<category><![CDATA[compression]]></category>
		<category><![CDATA[optimisation]]></category>
		<category><![CDATA[processing]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=405</guid>
		<description><![CDATA[Just recently I was optimising the processing time for a rather large cube on my laptop. The hardware I used was not tremendously powerful (a mobile i5 CPU, 8Gb RAM and one 7200 RPM hard disk) and having a 500M rows fact table proved to be somewhat of a challenge for it. The set up [...]]]></description>
			<content:encoded><![CDATA[<p>Just recently I was optimising the processing time for a rather large cube on my laptop. The hardware I used was not tremendously powerful (a mobile i5 CPU, 8Gb RAM and one 7200 RPM hard disk) and having a 500M rows fact table proved to be somewhat of a challenge for it.</p>
<p>The set up was fairly typical – a large fact table, with a few dimensions in a typical star schema. The goal was to get it to process as fast as possible.</p>
<p>After ensuring all best-practice advice from Microsoft (and in particular SQL CAT) was followed, I managed to get the processing down from 7381.075 seconds to 5801.536 s (approximately 21% improvement). However, one thing still did not look quite right – the CPU utilisation during the partition processing phase.</p>
<p>Considering my hardware configuration it was easy to deduce that the HDD would be more of a bottleneck than the CPU. There was only one HDD and everything, including the source database and the SSAS files, was on it. During the partition processing reading and writing is happening simultaneously, which is not good for performance. At the same time in my case the CPU utilisation was on around 75% with 25% to spare, which was not great. Ideally, I would like to see my CPU on 100%, or very close to that to ensure that I am utilising all of its power. However, I had no way to add more disks.</p>
<p>Luckily, in SQL Server 2008 (Enterprise Edition) we have the option to compress database tables, or partitions. We do get a performance hit on the CPU when we (de)compress the data, but it takes less space on the disk and thus requires less IOPS to read it. It sounded like a perfect fit for my problem. After estimating the benefits in terms of size row and page compression gave me, I decided to go with the heavier option since even its marginally better (5%) reduction of size over row-level compression was desirable. After waiting patiently for the compression operation to finish, the overall database size did drop to around 30% as predicted.</p>
<p>I run my SSAS processing script again and it completed in 4805.408 seconds – approximately 17% better than the previous run, which is a very significant improvement. The CPU utilisation went up to around 97%, which also meant that my blunder with the page vs. row compression produced, generally, good results.</p>
<p>One thing we must always consider is whether the bottleneck is in the IO. A few months later I replaced my hard disk with a new SSD (OSZ Vertex 2), which increased the IO performance of my laptop <strong>dramatically</strong>. When I tested SSAS processing tasks I could almost always see my CPU steady at 100% without any compression. If I were to compress my fact tables I would expect to get worse performance because my CPU would struggle to both decompress and process the data at the same time.</p>
<p>In conclusion, you must know what your bottleneck is before you opt for a solution like compression. It comes at a price, but the price may well be worth paying if your system is not well balanced.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2011/06/database-compression-effects-on-ssas-processing/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Debugging SSAS Cubes &#8211; a Few Tips</title>
		<link>http://www.bp-msbi.com/2011/06/debugging-ssas-cubes-a-few-tips/</link>
		<comments>http://www.bp-msbi.com/2011/06/debugging-ssas-cubes-a-few-tips/#comments</comments>
		<pubDate>Mon, 20 Jun 2011 03:21:54 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[SSAS]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[troubleshooting]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=402</guid>
		<description><![CDATA[There are a few techniques which can contribute to this topic and I will list some tips which seem to elude many people experiencing problems with their implementations. 1. Do not use the Cube Browser and Excel for troubleshooting Yes, it is convenient to just drag-drop some hierarchies and measures in the Cube Browser, or [...]]]></description>
			<content:encoded><![CDATA[<p>There are a few techniques which can contribute to this topic and I will list some tips which seem to elude many people experiencing problems with their implementations.</p>
<p><strong>1. Do not use the Cube Browser and Excel for troubleshooting</strong></p>
<p>Yes, it is convenient to just drag-drop some hierarchies and measures in the Cube Browser, or in Excel, but when you have troubles with your results these tools will obscure the results. This is happening because every client tool has to generate MDX and by doing so they often generalise the approach and add &#8220;nice&#8221; language constructs like VisualTotals, or always use a subselect clause. There is nothing wrong with checking the end-result of your work with tools showing what your users see, but when your calcs don&#8217;t behave the way you expect (especially when filtering things), I would definitely stay away from GUI clients. Instead you can write some MDX in SSMS and pull exactly what you need in a clean and straight-forward way. We can play with swapping WHERE clauses for subselects, add calculations directly in the queries, etc &#8211; in brief, we get the full calculation power of MDX in our hands for troubleshooting. Additionally, next time you ask a question someone else you can start with &#8220;I have this MDX query&#8230;&#8221; instead of: &#8220;I have this pivot grid in Product X&#8230;&#8221; &#8211; it is much more likely that you will get a meaningful response.</p>
<p><strong>2. Use SQL Server Profiler</strong></p>
<p>If your MDX works perfectly fine against your cube, but when you use Excel 20xx you get funny results, there is no better way to find what the problem is than to run a trace with SQL Server Profiler, capture the MDX the tool has generated and then work with that to debug &#8211; again in SSMS. Different versions of Excel generate different MDX and the difference can be very important. When using other tools the differences become even larger. The only way to see what your tools does (other than talk to the people who have built it) is to capture its SSAS queries.</p>
<p><strong>3. Ask for help</strong></p>
<p>Once you have arrived at the conclusion that you need help (e.g. after exhaustively searching for the problem online), you can quickly get an answer at a few forums. My preferred one is MDSN, which has a dedicated <a href="http://social.msdn.microsoft.com/Forums/en/sqlanalysisservices/threads">SSAS section</a>. Also, you can ask at the <a href="http://ssas-info.com/forum">www.ssas-info.com forum section</a>, or even at <a href="http://stackoverflow.com/questions/tagged/mdx">StackOverflow</a>. Either way, you will need to know what the versions of each product you are using are (especially SQL Server version, service packs and updates applied) and ideally &#8211; post your MDX (if you have 10 pages of queries it would help to somehow abbreviate the repeating sections instead of copy-pasting the lot). Do not also forget that the people who are reading your questions do not know your dimensional model and what features of SSAS you are using (e.g. LastNonEmpty, unary operators, etc.) &#8211; make sure that you describe any specifics &#8211; otherwise everyone would assume a typical star with a straight-forward implementation in SSAS. These approaches, together with being courteous and good with spelling and grammar, will help attract fellow developers, who may know a little SSAS quirk, or MDX feature which resolves your issue.</p>
<p><strong>4. Use Adventure Works</strong></p>
<p>Replicating you problems in Adventure Works is another great way to ensure you get an accurate answer. Because typically <em>everyone</em> on the forums has access to Adventure Works, showing some MDX which results in an unexpected for you outcomes is the best way to pinpoint the problem eliminating all question marks which your specific model and data could be introducing. Additionally, you will probably get an answer which includes some sample code and you will be able to run it immediately and see the results.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2011/06/debugging-ssas-cubes-a-few-tips/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

