<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Boyan Penev on Microsoft BI</title>
	
	<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>Wed, 21 Mar 2012 00:22:35 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/bp-msbi" /><feedburner:info uri="bp-msbi" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><creativeCommons:license>http://creativecommons.org/licenses/by/2.5/</creativeCommons:license><item>
		<title>Counting Number of Queries Executed in SSAS</title>
		<link>http://feedproxy.google.com/~r/bp-msbi/~3/L3-pKJLngFY/</link>
		<comments>http://www.bp-msbi.com/2012/02/counting-number-of-queries-executed-in-ssas/#comments</comments>
		<pubDate>Thu, 23 Feb 2012 02:13:06 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[SSAS]]></category>
		<category><![CDATA[administration]]></category>
		<category><![CDATA[monitoring]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=498</guid>
		<description><![CDATA[When monitoring SSAS we can use a few tools to gain insight into what is happening on the instance. Perfmon is especially interesting as it shows us information about various aspects of the server – we can see memory, disk, CPU and MDX counters out of the box. However, perfmon cannot show us how many [...]]]></description>
			<content:encoded><![CDATA[<p>When monitoring SSAS we can use a few tools to gain insight into what is happening on the instance. Perfmon is especially interesting as it shows us information about various aspects of the server – we can see memory, disk, CPU and MDX counters out of the box. However, perfmon cannot show us how many queries were run on SSAS – neither per period (e.g. second), nor in total since the service had started. We have another counter, similar to a count of queries – <strong>Storage Engine Query : Total Queries Answered</strong>. This is not the same as the number of MDX queries answered, as if a query does not hit the Storage Engine (SE), but the Formula Engine (FE) cache instead, it won&#8217;t increment the counter. And, if a query needs to be answered by more than one Storage Engine requests, we will see that the counter gets incremented with more than 1.</p>
<p>There are alternatives. We can try using the Query Log server settings and save queries to a database table automatically:</p>
<p><img src="http://www.bp-msbi.com/wp-content/uploads/2012/02/022312_0212_CountingNum1.png" alt="" /></p>
<p>Unfortunately (for us in this case), since the Query Log is typically used for Usage Based Optimisations (UBO), it also shows SE requests, not the actual MDX queries issued. Hence, it suffers from the same drawback as the perfmon Total Queries Answered counter.</p>
<p>The other alternative which comes to mind is SQL Server Profiler. After all it allows us to see what queries get sent to the server, along with lots of other useful information. If we are interested in the count of queries only, we can capture a trace which includes only the Query End event. Why not Query Begin? Well, we can&#8217;t see some possibly interesting numbers before the query has been executed, for example the Duration of each query. If we capture only Query End we get exactly what we need – one event per query. We can also capture Error events to check if things go wrong.</p>
<p>A typical Query End-only trace looks like this (all columns included):</p>
<p><img src="http://www.bp-msbi.com/wp-content/uploads/2012/02/022312_0212_CountingNum2.png" alt="" /></p>
<p><img src="http://www.bp-msbi.com/wp-content/uploads/2012/02/022312_0212_CountingNum3.png" alt="" /></p>
<p>As we can see above, we get the actual query in the TextData column, the User Name, Application Name, Duration, Database Name – all very useful properties if we want to analyse the load and the performance of our server and various solutions. While the information looks great on screen, having it in a database table would enable us to do what we (BI devs) like doing – play with the data. Only this time it&#8217;s our data, about our toys, so it (at least for me) is twice as fun.</p>
<p>A SSAS trace can be run on the server without Profiler – the term for it is a &#8220;server-side trace&#8221;. Unlike SQL Server RDBMS traces, a SSAS server-side trace cannot directly log its output to a SQL Server table. Luckily, we can write the results in a &#8220;.trc&#8221; file, which in turn can be imported into a SQL Server table with a few lines of code.</p>
<p>To create a server-side trace we can first export the trace definition to an XMLA file from profiler:</p>
<p><img src="http://www.bp-msbi.com/wp-content/uploads/2012/02/022312_0212_CountingNum4.png" alt="" /></p>
<p>The XMLA file we get looks like this (all scripts are attached to the end of this post):</p>
<p><img src="http://www.bp-msbi.com/wp-content/uploads/2012/02/022312_0212_CountingNum5.png" alt="" /></p>
<p>If we remove the first line (?xml version…), we can run this and it will create a trace on the server. This trace is useless to us because it does not write its output anywhere. To fix this we can add a few settings like this:</p>
<p><img src="http://www.bp-msbi.com/wp-content/uploads/2012/02/022312_0212_CountingNum6.png" alt="" /></p>
<p>Note that I have changed the Name and ID of the trace to be more user-friendly, and I have removed the Filers section, as well as the first line. Now the script can be used to create a trace. To delete the trace we can use:</p>
<p><img src="http://www.bp-msbi.com/wp-content/uploads/2012/02/022312_0212_CountingNum7.png" alt="" /></p>
<p>And to list all running traces on a SSAS instance:</p>
<p><img src="http://www.bp-msbi.com/wp-content/uploads/2012/02/022312_0212_CountingNum8.png" alt="" /></p>
<p>Note that by default SSAS is configured to run Flight Recorder, which uses a trace to capture events happening on the server (thanks to <a href="http://denglishbi.wordpress.com/">Dan English </a>for suggesting this clarification). The trace may appear with ID and Name of <strong>FlightRecorder</strong>. You should not tamper with the trace manually. If you want to stop it, which is a performance recommendation from the SSAS Performance Guide, you should disable Flight Recorder from the SSAS server properties (click for a larger version):</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2012/02/09-Flight-Recorder-Disable.png"><img class="alignnone  wp-image-501" title="09 - Flight Recorder - Disable" src="http://www.bp-msbi.com/wp-content/uploads/2012/02/09-Flight-Recorder-Disable.png" alt="" width="521" height="379" /></a></p>
<p>Now, armed with all these scripts we can effectively manage traces on our instances. The only problem we have not resolved so far is exporting the trc file created by our create trace XMLA command to a database table. This can be easily done in a .NET app, or in PowerShell. The ps_trace_copy_to_table.ps1 PowerShell script does the following (thanks to <a href="http://geekswithblogs.net/darrengosbell/Default.aspx">Darren Gosbell</a> for creating the initial version).</p>
<ol>
<li>Copy the trc file with another name for further processing</li>
<li>Delete the trace form the server</li>
<li>Delete the trace file</li>
<li>Start the trace on the server again</li>
<li>Export the copied trc file into a SQL Server table</li>
<li>Run a stored procedure moving the data from the SQL Server table to another SQL Server table which contains all trace data</li>
</ol>
<p>We delete-&gt;create the trace because otherwise we cannot delete the trace file. The last step runs a stored procedure which moves the data from the table we imported into to another table because the first (landing) table gets re-created every time we import into it and the trace data cannot persist in it.</p>
<p>Note that there is some exception handling implemented in this script (try/catch/finally blocks). If you are using an old version of PowerShell, it is possible that you may have to remove the exception handling statements as they were not supported. I have attached a sample script which excludes them (ps_trace_copy_to_table_no_exception_handling.ps1).</p>
<p>Finally, we can run this script through SQL Server Agent on regular intervals. SQL Server Agent allows direct PowerShell script execution, so this is very easy to set up and can be scheduled to run recurrently every X minutes/hours/days.</p>
<p>A small note: you may notice that some rows in the database table contain events with an Event Class &lt;&gt; 10 (10 is Query End) and NULLs in most columns. These are trace-related events and can be ignored (e.g. your stored procedure moving the data form one table to another can skip such rows).</p>
<p>There is also another way to achieve the same outcome. As a part of the Microsoft SQL Server samples you can download a utility called <a href="http://sqlsrvanalysissrvcs.codeplex.com/releases/">ASTrace</a>. You will have to download and compile it, but after that you can run it as a Windows service and it will capture the trace events as they happen and write them directly to a SQL table. The Server -&gt; File -&gt; Table changes to Server -&gt; Table. Also, you don&#8217;t need to move the data from one table to another. The drawback is that you have an additional service on your server. You may or may not be able to run it (depending on your organisation&#8217;s security policies and admin practices), and while it is open source, it is not officially supported by Microsoft.</p>
<p>Either way, collecting trace data allows you to create reports like the following, which can be a really nice way to track what&#8217;s happening on your servers:</p>
<p><img src="http://www.bp-msbi.com/wp-content/uploads/2012/02/022312_0212_CountingNum9.png" alt="" /></p>
<p><img src="http://www.bp-msbi.com/wp-content/uploads/2012/02/022312_0212_CountingNum10.png" alt="" /></p>
<p>Scripts:</p>
<p><small><div id='filelist1'><ul id="listyofiles">
<li><a href="http://www.bp-msbi.com/wp-content/count_queries_scripts/create_trace.xmla">create_trace.xmla</a></li>
<li><a href="http://www.bp-msbi.com/wp-content/count_queries_scripts/delete_trace.xmla">delete_trace.xmla</a></li>
<li><a href="http://www.bp-msbi.com/wp-content/count_queries_scripts/discover_trace.xmla">discover_trace.xmla</a></li>
<li><a href="http://www.bp-msbi.com/wp-content/count_queries_scripts/ps_trace_copy_to_table.ps1">ps_trace_copy_to_table.ps1</a></li>
<li><a href="http://www.bp-msbi.com/wp-content/count_queries_scripts/ps_trace_copy_to_table_no_exception_handling.ps1">ps_trace_copy_to_table_no_exception_handling.ps1</a></li>
<li><a href="http://www.bp-msbi.com/wp-content/count_queries_scripts/usp_copy_data_to_perm.sql">usp_copy_data_to_perm.sql</a></li>
</ul>
</div>
</small></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/bp-msbi?a=L3-pKJLngFY:Nbflq2IPBp4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=L3-pKJLngFY:Nbflq2IPBp4:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/bp-msbi?i=L3-pKJLngFY:Nbflq2IPBp4:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=L3-pKJLngFY:Nbflq2IPBp4:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=YwkR-u9nhCs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/bp-msbi/~4/L3-pKJLngFY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2012/02/counting-number-of-queries-executed-in-ssas/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		<feedburner:origLink>http://www.bp-msbi.com/2012/02/counting-number-of-queries-executed-in-ssas/</feedburner:origLink></item>
		<item>
		<title>What Exists and What is Empty in MDX</title>
		<link>http://feedproxy.google.com/~r/bp-msbi/~3/EP_gfKlEWkg/</link>
		<comments>http://www.bp-msbi.com/2012/02/what-exists-and-what-is-empty-in-mdx/#comments</comments>
		<pubDate>Sun, 12 Feb 2012 07:05:39 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[SSAS]]></category>
		<category><![CDATA[empty cells]]></category>
		<category><![CDATA[MDX]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=477</guid>
		<description><![CDATA[After reading my chapter &#8220;Managing Context in MDX&#8221; in MVP Deep Dives vol2 I noticed that I should have probably discussed one extra topic &#8211; the difference between cells which cannot exist, and such which can, but are empty. The basic idea is that in SSAS cubes we have the notion of empty space. However, there [...]]]></description>
			<content:encoded><![CDATA[<p>After reading my chapter &#8220;Managing Context in MDX&#8221; in MVP Deep Dives vol2 I noticed that I should have probably discussed one extra topic &#8211; the difference between cells which cannot exist, and such which can, but are empty.</p>
<p>The basic idea is that in SSAS cubes we have the notion of empty space. However, there is an important difference between empty intersections which are possible but result in nulls when queried and &#8220;impossible&#8221; intersections between hierarchies in the same dimension.</p>
<p>If we look at the Date dimension in Adventure Works we can see that we have month and year attributes. Months in 2007 appear only with the year 2007 in the dimension. Therefore, the combination between January 2005 and CY 2007 is not possible and consequentially it does not and cannot exist in our cube. In contrast, if we query for Clothing products in 2007 and we place the Month attribute on rows, we can see that there has been no Clothing items sold in the first few months of 2007:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2012/02/01_query.png"><img class="size-full wp-image-479 alignnone" title="01_query" src="http://www.bp-msbi.com/wp-content/uploads/2012/02/01_query.png" alt="" width="463" height="512" /></a></p>
<p>Here we are dealing with possible, but empty cells – the January 2007 to June 2007 rows show empty intersections in the cube.</p>
<p>Why is this important? Well, it means that if we try to get the number of months with Clothing sales in 2007 with a query like:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2012/02/02_query.png"><img class="alignnone size-full wp-image-480" title="02_query" src="http://www.bp-msbi.com/wp-content/uploads/2012/02/02_query.png" alt="" width="477" height="444" /></a></p>
<p>we wrongly get 12, not 6. We need a function which can &#8220;detect&#8221; empty cells – not unnecessarily enforce the current context. An excellent function for this purpose is NonEmpty (or Exists):</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2012/02/03_query.png"><img class="alignnone size-full wp-image-481" title="03_query" src="http://www.bp-msbi.com/wp-content/uploads/2012/02/03_query.png" alt="" width="477" height="445" /></a></p>
<p>Here we get the expected number – 6 (since only 6 months in 2007 have Internet Sales Amount against them).</p>
<p>A similar example can be shown the other way around. The following query returns 37, which is the total number of members of the month attribute with data against them:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2012/02/04_query.png"><img class="alignnone size-full wp-image-482" title="04_query" src="http://www.bp-msbi.com/wp-content/uploads/2012/02/04_query.png" alt="" width="428" height="444" /></a></p>
<p>This is because the NonEmpty function does not enforce the current context on its first argument and it gives us the members with data only (omitting NonEmpty results in 39, because we have two months with no sales whatsoever). Existing does, so if we add Existing to NonEmpty we get the expected count of 12 (as all months have had a sale in 2007 if we take all categories into account):</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2012/02/06_query2.png"><img class="alignnone size-full wp-image-487" title="06_query" src="http://www.bp-msbi.com/wp-content/uploads/2012/02/06_query2.png" alt="" width="464" height="443" /></a></p>
<p>Here we eliminated the impossible intersections between months not in 2007 and year 2007.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/bp-msbi?a=EP_gfKlEWkg:vQ8jfNpyX8k:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=EP_gfKlEWkg:vQ8jfNpyX8k:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/bp-msbi?i=EP_gfKlEWkg:vQ8jfNpyX8k:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=EP_gfKlEWkg:vQ8jfNpyX8k:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=YwkR-u9nhCs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/bp-msbi/~4/EP_gfKlEWkg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2012/02/what-exists-and-what-is-empty-in-mdx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.bp-msbi.com/2012/02/what-exists-and-what-is-empty-in-mdx/</feedburner:origLink></item>
		<item>
		<title>SSAS Locale Identifier Bug</title>
		<link>http://feedproxy.google.com/~r/bp-msbi/~3/lmJMCnPx4kg/</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">https://connect.microsoft.com/SQLServer/feedback/details/721372/locale-identifier-bug</a></p>
<p><em><strong>Note (2012-03-21):</strong> The issue seems to be with Windows Vista+ as confirmed by Michael Kaplan &#8211; <a href="http://blogs.msdn.com/b/michkap/archive/2010/03/19/9980203.aspx">http://blogs.msdn.com/b/michkap/archive/2010/03/19/9980203.aspx</a></em></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/bp-msbi?a=lmJMCnPx4kg:R_zH8Na0Ycg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=lmJMCnPx4kg:R_zH8Na0Ycg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/bp-msbi?i=lmJMCnPx4kg:R_zH8Na0Ycg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=lmJMCnPx4kg:R_zH8Na0Ycg:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=YwkR-u9nhCs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/bp-msbi/~4/lmJMCnPx4kg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2012/01/ssas-locale-identifier-bug/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		<feedburner:origLink>http://www.bp-msbi.com/2012/01/ssas-locale-identifier-bug/</feedburner:origLink></item>
		<item>
		<title>Load Testing BI Solutions – When?</title>
		<link>http://feedproxy.google.com/~r/bp-msbi/~3/HzkoTQBcnG0/</link>
		<comments>http://www.bp-msbi.com/2011/12/load-testing-bi-solutions-when/#comments</comments>
		<pubDate>Fri, 23 Dec 2011 23:58:56 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[Other]]></category>
		<category><![CDATA[Load Testing]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=470</guid>
		<description><![CDATA[This year I came across two very different BI projects which had the common non-functional requirement to prove that they would handle an expected spike in the report generation load. Funny enough, in both cases the project teams got very concerned and came up with wildly inaccurate predictions of how many concurrent users we should [...]]]></description>
			<content:encoded><![CDATA[<p>This year I came across two very different BI projects which had the common non-functional requirement to prove that they would handle an expected spike in the report generation load. Funny enough, in both cases the project teams got very concerned and came up with wildly inaccurate predictions of how many concurrent users we should be testing for. In the first case the problem was with the perception of “thousands of users”, while in the second, the team interpreted “monthly users” as “concurrent users”. The annoying part was that in the first case the team planned on building an ultra-massively overcomplicated queuing system to handle those spikes, and in the second case they were thinking of completely scrapping the ad-hoc functionality in the solution and resorting to report extracts distributed by email. The unreasonable expectations of the load lead to bad design choices – this is why it is important to <strong>remain calm and first check whether there is a problem at all.</strong></p>
<p>Firstly, let’s agree that we are measuring report requests. To begin, we should know how many requests we get per a period of time (e.g. a month), and then how long it takes to generate a report. A typical scenario would be:</p>
<ul>
<li>1,000,000 report requests per month</li>
<li>2 seconds to generate a report on average</li>
</ul>
<p>What we need to do now if apply a bit of math:</p>
<p>1,000,000 / 20 = 50,000 requests per day (on average)</p>
<p>50,000 / 8 = 6,250 requests per hour (8 hours in a working day)</p>
<p>Since a report takes 2 seconds to generate, we can generate 1,800 reports in one hour. Therefore, with 6,250 requests, we would have 3.47 average concurrent users. Of course, this would be the case if we have a very uniformly split load. In reality this would not happen – instead, we will have peaks and dips in usage. A moderate peak is typically around 3x the average, while a heavy one would be at around 6x the average. To ensure that we can handle such peak periods, we should multiply our average concurrent users by 3 or by 6 depending on our load analysis. Let’s assume we have a very high peak load of 3.47 * 6 = 20.82, or approximately 21 concurrent users. This is the number we need to test in our case. Note that we had 1,000,000 report requests per month, but in our highest peak we expect to have only 21 concurrent users. I have not actually had a project where we have expected to have such a load (in both cases which prompted me to write this post we had between 2000-10000 users per month).</p>
<p>The moral of the story – don’t panic. In most reporting projects the user load is not high enough to warrant a full-scale load testing exercise; next time you hear talking about something like that, instead of rushing to cover unreasonable scenarios, try to calculate and confirm the need first.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/bp-msbi?a=HzkoTQBcnG0:hgrG_ZENrqc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=HzkoTQBcnG0:hgrG_ZENrqc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/bp-msbi?i=HzkoTQBcnG0:hgrG_ZENrqc:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=HzkoTQBcnG0:hgrG_ZENrqc:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=YwkR-u9nhCs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/bp-msbi/~4/HzkoTQBcnG0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2011/12/load-testing-bi-solutions-when/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.bp-msbi.com/2011/12/load-testing-bi-solutions-when/</feedburner:origLink></item>
		<item>
		<title>DataMarket Updates: Speed, Portal and DateStream</title>
		<link>http://feedproxy.google.com/~r/bp-msbi/~3/lxFH-b6gv6Q/</link>
		<comments>http://www.bp-msbi.com/2011/12/datamarket-updates-speed-portal-and-datestream/#comments</comments>
		<pubDate>Thu, 08 Dec 2011 00:08:19 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[Other]]></category>
		<category><![CDATA[DataMarket]]></category>
		<category><![CDATA[DateStream]]></category>
		<category><![CDATA[updates]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=469</guid>
		<description><![CDATA[It has been an eventful week for the Azure DataMarket. We had three new and exciting (for geeks like me) things happening in that corner of the Microsoft universe: 1. Speed! There was an update to the Azure DataMarket a few days ago. It was, in my opinion, the best thing Microsoft could have done [...]]]></description>
			<content:encoded><![CDATA[<p>It has been an eventful week for the Azure DataMarket. We had three new and exciting (for geeks like me) things happening in that corner of the Microsoft universe:</p>
<h5>1. Speed!</h5>
<p>There was an update to the Azure DataMarket a few days ago. It was, in my opinion, the best thing Microsoft could have done to their offering &#8211; tremendously increase its performance. While the DataMarket was previously plagued by unacceptably slow download speed, now it&#8217;s for feed standards blazingly fast. For comparison sake, I used to wait for more than 40 minutes when downloading an approximately 70k rows feed from the DataMarket prior to the update. Now, it is on my machine in around 5 &#8211; 8-fold increase in performance! Rumours have it that on faster-than-my-home-ADSL2+-networks we will be experiencing up to 20x better performance. It would be good to hear if this is actually correct for developers on such networks (please comment).</p>
<p>Next, range queries, hopefully&#8230;</p>
<h5>2. Portal</h5>
<p>While before the last couple of days anyone who wanted to publish data on the DataMarket had to contact the Microsoft team via email and ask how to get it done, we have just moved into the self-service space with a new portal allowing publishers to create and manage their feeds. The link to this new portal is:</p>
<p><a href="https://publish.marketplace.windowsazure.com/">https://publish.marketplace.windowsazure.com/</a></p>
<p>And, you can find some very helpful documentation about it here:</p>
<p><a href="http://msdn.microsoft.com/en-us/library/windowsazure/hh563871.aspx">http://msdn.microsoft.com/en-us/library/windowsazure/hh563871.aspx</a></p>
<h5>3. DateStream</h5>
<p>Finally, I am proud to announce that the great <a href="https://datamarket.azure.com/dataset/1542c52d-d466-4094-a801-9ef8fd7c6485">DateStream </a>feed got translated in four more languages:</p>
<p>- <strong>Hebrew</strong> and <strong>Danish</strong> &#8211; thanks to <a href="http://sqlserverjedi.wordpress.com/">Rafi Asraf</a></p>
<p>- <strong>German</strong></p>
<p>- <strong>Bulgarian</strong></p>
<p>The <strong>Italian</strong> translation (thanks to <a href="http://sqlblog.com/blogs/marco_russo/">Marco Russo</a>) is coming soon too, but missed this release unfortunately.</p>
<p>Feel free to explore them and let me know if anything needs to be changed to make them more correct/useful.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/bp-msbi?a=lxFH-b6gv6Q:R47BKadQOp8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=lxFH-b6gv6Q:R47BKadQOp8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/bp-msbi?i=lxFH-b6gv6Q:R47BKadQOp8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=lxFH-b6gv6Q:R47BKadQOp8:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=YwkR-u9nhCs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/bp-msbi/~4/lxFH-b6gv6Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2011/12/datamarket-updates-speed-portal-and-datestream/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.bp-msbi.com/2011/12/datamarket-updates-speed-portal-and-datestream/</feedburner:origLink></item>
		<item>
		<title>SSAS: Multiple SQL Queries in ROLAP Mode</title>
		<link>http://feedproxy.google.com/~r/bp-msbi/~3/ipMOpOFUX3U/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/bp-msbi?a=ipMOpOFUX3U:A3ilYJud10Y:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=ipMOpOFUX3U:A3ilYJud10Y:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/bp-msbi?i=ipMOpOFUX3U:A3ilYJud10Y:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=ipMOpOFUX3U:A3ilYJud10Y:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=YwkR-u9nhCs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/bp-msbi/~4/ipMOpOFUX3U" height="1" width="1"/>]]></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>
		<feedburner:origLink>http://www.bp-msbi.com/2011/11/ssas-multiple-sql-queries-in-rolap-mode/</feedburner:origLink></item>
		<item>
		<title>Melbourne SQL Server Social Event: Short Notice!</title>
		<link>http://feedproxy.google.com/~r/bp-msbi/~3/_O15chMARx4/</link>
		<comments>http://www.bp-msbi.com/2011/11/melbourne-sql-server-social-event-short-notice/#comments</comments>
		<pubDate>Tue, 15 Nov 2011 23:59:55 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[Other]]></category>
		<category><![CDATA[event]]></category>
		<category><![CDATA[SQL Server]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=454</guid>
		<description><![CDATA[A short notice for SQL Server enthusiasts/professionals in Melbourne. Stephen Few is in town and will attend the SQL Server Social Event tomorrow (17 Nov) at the Sherlock Holmes Inn in the CBD (415 Collins Street). Feel free to come and meet the community, talk about SQL Server and information visualisation..and possibly get your Stephen [...]]]></description>
			<content:encoded><![CDATA[<p>A short notice for SQL Server enthusiasts/professionals in Melbourne. <a href="http://www.perceptualedge.com/">Stephen Few</a> is in town and will attend the SQL Server Social Event tomorrow (17 Nov) at the Sherlock Holmes Inn in the CBD (415 Collins Street). Feel free to come and meet the community, talk about SQL Server and information visualisation..and possibly get your Stephen Few books signed.</p>
<p>Link for the event: <a href="http://sqlserversocial.eventbrite.com/">http://sqlserversocial.eventbrite.com/</a></p>
<p>See you there!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/bp-msbi?a=_O15chMARx4:YKxFJ-Vi9uI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=_O15chMARx4:YKxFJ-Vi9uI:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/bp-msbi?i=_O15chMARx4:YKxFJ-Vi9uI:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=_O15chMARx4:YKxFJ-Vi9uI:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=YwkR-u9nhCs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/bp-msbi/~4/_O15chMARx4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2011/11/melbourne-sql-server-social-event-short-notice/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.bp-msbi.com/2011/11/melbourne-sql-server-social-event-short-notice/</feedburner:origLink></item>
		<item>
		<title>Alternate Ordering of Attributes in SSAS</title>
		<link>http://feedproxy.google.com/~r/bp-msbi/~3/FV55GdNTFIc/</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>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/bp-msbi?a=FV55GdNTFIc:NyJj_VilFUs:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=FV55GdNTFIc:NyJj_VilFUs:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/bp-msbi?i=FV55GdNTFIc:NyJj_VilFUs:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=FV55GdNTFIc:NyJj_VilFUs:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=YwkR-u9nhCs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/bp-msbi/~4/FV55GdNTFIc" height="1" width="1"/>]]></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>
		<feedburner:origLink>http://www.bp-msbi.com/2011/11/alternate-ordering-of-attributes-in-ssas/</feedburner:origLink></item>
		<item>
		<title>Range Queries with Azure DataMarket Feeds</title>
		<link>http://feedproxy.google.com/~r/bp-msbi/~3/xH-eXLsCyTo/</link>
		<comments>http://www.bp-msbi.com/2011/10/range-queries-with-azure-datamarket-feeds/#comments</comments>
		<pubDate>Mon, 17 Oct 2011 03:32:45 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[PowerPivot]]></category>
		<category><![CDATA[DataMarket]]></category>
		<category><![CDATA[DateStream]]></category>
		<category><![CDATA[feeds]]></category>
		<category><![CDATA[OData]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=441</guid>
		<description><![CDATA[By default the Azure DataMarket does not allow range queries. In fact, the only way we can filter a data feed is through specifying one or more values for the &#8220;queryable&#8221; fields specified for it. There is not technical reason behind not allowing range queries as both the back-end (presumably SQL Azure, or SQL Server) [...]]]></description>
			<content:encoded><![CDATA[<p>By default the Azure DataMarket does not allow range queries. In fact, the only way we can filter a data feed is through specifying one or more values for the &#8220;queryable&#8221; fields specified for it. There is not technical reason behind not allowing range queries as both the back-end (presumably SQL Azure, or SQL Server) and the OData protocol support them. Fortunately, there is a way to consume a range of the values in a column of a data feed in PowerPivot. It is not straight-forward and I do not think that the target audience of both self-service BI/PowerPivot and the DataMarket itself would appreciate the complexity, but it could be useful anyway.</p>
<p>If we want to pull all three tables from the DataMarket we can simply use <strong><span style="color: #800000;">https://api.datamarket.azure.com/BoyanPenev/DateStream/</span></strong> as the URL in PowerPivot:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/10/ppvt-query-01.png"><img class="alignleft size-full wp-image-442" title="PowerPivot full feed query" src="http://www.bp-msbi.com/wp-content/uploads/2011/10/ppvt-query-01.png" alt="" width="532" height="544" /></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>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>Otherwise, we can pick each one with a URL like (for the BasicCalendarEngish table):</p>
<p><strong><span style="color: #800000;">https://api.datamarket.azure.com/Data.ashx/BoyanPenev/DateStream/BasicCalendarEnglish</span></strong></p>
<p>If we filter the data set on the DataMarket website to request only the data for 2010 we get the following URL:</p>
<p><span style="color: #800000;"><strong>https://api.datamarket.azure.com/Data.ashx/BoyanPenev/DateStream/BasicCalendarEnglish?$filter=YearKey%20eq%202010</strong></span></p>
<p>Note the last bit:</p>
<p><strong><span style="color: #800000;">?$filter=YearKey%20eq%202010</span></strong></p>
<p>This is simply the URL/OData encoded <strong><span style="color: #800000;">?$filter=YearKey = 2010</span></strong></p>
<p>In OData we can also use other operators, not just = (or <strong><span style="color: #ff0000;">eq</span></strong>). For ranges these are <span style="color: #ff0000;"><strong>gt</strong></span> (greater than), <span style="color: #ff0000;"><strong>ge</strong></span> (greater than or equal to), <span style="color: #ff0000;"><strong>lt</strong></span> (less than) and <span style="color: #ff0000;"><strong>le</strong></span> (less than or equal to). We can also use <span style="color: #ff0000;"><strong>and</strong></span> and <span style="color: #ff0000;"><strong>or</strong></span> operators to combine different predicates. For a more thorough list, please refer to <a href="http://www.odata.org/developers/protocols/uri-conventions">http://www.odata.org/developers/protocols/uri-conventions</a>. If we replace the &#8221; = 2010&#8243; with &#8221; &lt; 2010&#8243; and then encode the URL, we do indeed get all years prior to 2010. Things get slightly more complicated when we have a more complex scenario. In example, when building a date table we may want to include all years between 2000 and 2030. To do that, we would have to write something like:</p>
<p><span style="color: #800000;"><strong>https://api.datamarket.azure.com/Data.ashx/BoyanPenev/DateStream/BasicCalendarEnglish?$filter=<span style="color: #000080;">YearKey &gt;= 2000 and YearKey &lt;= 2030</span></strong></span></p>
<p>encoded, the same looks like this:</p>
<p><span style="color: #800000;"><strong>https://api.datamarket.azure.com/Data.ashx/BoyanPenev/DateStream/BasicCalendarEnglish?$filter=<span style="color: #000080;">YearKey<span style="color: #33cccc;">%20</span><span style="color: #ff0000;">ge</span><span style="color: #33cccc;">%20</span>2000<span style="color: #33cccc;">%20</span><span style="color: #ff0000;">and</span><span style="color: #33cccc;">%20</span>YearKey<span style="color: #33cccc;">%20</span><span style="color: #ff0000;">le</span><span style="color: #33cccc;">%20</span>2030</span></strong></span></p>
<p>Here <span style="color: #33cccc;"><strong>space</strong></span> is <span style="color: #33cccc;"><strong>%20</strong><span style="color: #000000;"> and the math comparison operators have been replaced with the OData operators (in <span style="color: #ff0000;">red</span>)</span></span>.</p>
<p>If we paste this in PowerPivot and hit &#8220;Next&#8221;:</p>
<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/10/ppvt-query-021.png"><img class="alignleft size-full wp-image-444" title="PowerPivot filtered feed" src="http://www.bp-msbi.com/wp-content/uploads/2011/10/ppvt-query-021.png" alt="" width="532" height="544" /></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>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>…we get exactly what we expect – a table with 30 years.</p>
<p>Things get more complicated if we include the datetime DateKey in the URL. For a single date (e.g. 1900-01-01), we have to use:</p>
<p><span style="color: #800000;"><strong>https://api.datamarket.azure.com/Data.ashx/BoyanPenev/DateStream/BasicCalendarEnglish?$filter=<span style="color: #000080;">DateKey = datetime&#8217;1900-01-01T00:00:00&#8242;</span></strong></span></p>
<p>After Applying URL encoding we get:</p>
<p><span style="color: #800000;"><strong>https://api.datamarket.azure.com/Data.ashx/BoyanPenev/DateStream/BasicCalendarEnglish?$filter=<span style="color: #000080;">DateKey<span style="color: #33cccc;">%20</span><span style="color: #ff0000;">eq</span><span style="color: #33cccc;">%20</span>datetime<span style="color: #33cccc;">%27</span>1900-01-01T00<span style="color: #33cccc;">%3a</span>00<span style="color: #33cccc;">%3a</span>00<span style="color: #33cccc;">%27</span></span></strong></span></p>
<p>Where<span style="color: #33cccc;"> %27</span> is <span style="color: #33cccc;">apostrophe <span style="color: #000000;">and</span></span> <span style="color: #33cccc;">%3a</span> is a <span style="color: #33cccc;">colon</span> (for a list of ASCII characters and their URL encoded form we can refer to <a href="http://www.w3schools.com/tags/ref_urlencode.asp">http://www.w3schools.com/tags/ref_urlencode.asp).</a></p>
<p>Now, to combine the two we would need to write:</p>
<p><span style="color: #800000;"><strong>https://api.datamarket.azure.com/Data.ashx/BoyanPenev/DateStream/BasicCalendarEnglish?$filter=<span style="color: #000080;">DateKey = datetime&#8217;1900-01-01T00:00:00&#8242; or (YearKey &gt;= 2000 and YearKey &lt;= 2030)</span></strong></span></p>
<p><span style="color: #000000;">Encoded this becomes:</span></p>
<p><span style="color: #800000;"><strong>https://api.datamarket.azure.com/Data.ashx/BoyanPenev/DateStream/BasicCalendarEnglish?$filter=<span style="color: #000080;">DateKey<span style="color: #33cccc;">%20</span><span style="color: #ff0000;">eq</span><span style="color: #33cccc;">%20</span>datetime<span style="color: #33cccc;">%27</span>1900-01-01T00<span style="color: #33cccc;">%3a</span>00<span style="color: #33cccc;">%3a</span>00<span style="color: #33cccc;">%27%20</span><span style="color: #ff0000;">or</span><span style="color: #33cccc;">%20%28</span>YearKey<span style="color: #33cccc;">%20</span><span style="color: #ff0000;">ge</span><span style="color: #33cccc;">%20</span>2000<span style="color: #33cccc;">%20</span><span style="color: #ff0000;">and</span><span style="color: #33cccc;">%20</span>YearKey<span style="color: #33cccc;">%20</span><span style="color: #ff0000;">le</span><span style="color: #33cccc;">%20</span>2030<span style="color: #33cccc;">%29</span></span></strong></span></p>
<p>This monstrous-to-write URL string returns 30 years of data + 1 day.</p>
<p>I suppose this approach can be classified as a workaround, as I have not seen any documentation on PowerPivot referring to any options for filtering data from the Azure DataMarket. However, in my opinion, this should be a feature of the DataMarket itself as it would make it easier/possible for users with any tool to get just the data they need and even possibly reduce the load on the site service since it will no longer be necessary to export everything and then attempt to apply a filter.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/bp-msbi?a=xH-eXLsCyTo:7tONrjFj1tI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=xH-eXLsCyTo:7tONrjFj1tI:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/bp-msbi?i=xH-eXLsCyTo:7tONrjFj1tI:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=xH-eXLsCyTo:7tONrjFj1tI:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=YwkR-u9nhCs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/bp-msbi/~4/xH-eXLsCyTo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2011/10/range-queries-with-azure-datamarket-feeds/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.bp-msbi.com/2011/10/range-queries-with-azure-datamarket-feeds/</feedburner:origLink></item>
		<item>
		<title>Introducing Project DateStream (CodePlex)</title>
		<link>http://feedproxy.google.com/~r/bp-msbi/~3/aX2FRRINoWk/</link>
		<comments>http://www.bp-msbi.com/2011/10/introducing-project-datestream-codeplex/#comments</comments>
		<pubDate>Thu, 06 Oct 2011 08:02:13 +0000</pubDate>
		<dc:creator>Boyan Penev</dc:creator>
				<category><![CDATA[PowerPivot]]></category>
		<category><![CDATA[Azure DataMarket]]></category>
		<category><![CDATA[date]]></category>
		<category><![CDATA[DateStream]]></category>
		<category><![CDATA[table]]></category>

		<guid isPermaLink="false">http://www.bp-msbi.com/?p=436</guid>
		<description><![CDATA[I recently blogged about The Case for an Azure DataMarket Date Table. I finished the blog post with a bit of a critique of the DataMarket team at Microsoft, which I can now wholeheartedly apologise for. This is because since my last post I was contacted by Max Uritsky who is a Group Program Manager [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.bp-msbi.com/wp-content/uploads/2011/10/feed-02.png"><img class="alignleft size-full wp-image-438" title="feed-02" src="http://www.bp-msbi.com/wp-content/uploads/2011/10/feed-02.png" alt="" width="201" height="152" /></a>I recently blogged about <a href="http://www.bp-msbi.com/2011/06/the-case-for-an-azure-datamarket-date-table/">The Case for an Azure DataMarket Date Table</a>. I finished the blog post with a bit of a critique of the DataMarket team at Microsoft, which I can now wholeheartedly apologise for. This is because since my last post I was contacted by Max Uritsky who is a Group Program Manager on the Windows Azure Marketplace DataMarket team (a long name for a team, yes). He and Belinda Tiberio managed to help me with creating and hosting a new Date feed. Not only they helped with making it available for free on the DataMarket website, but also gave me a 1Gb free SQL Azure database for the project. A big &#8220;thank you&#8221; goes to Julie Strauss from the SSAS team for making the contact, as well.</p>
<p>To summarise, the DateStream project is a free date table available as a feed and intended to be used by PowerPivot BI users. As most, if not all, BI projects include a date table, the goal is to provide an easy-to-use, correct and simple mechanism for creating such tables.</p>
<p>After some deliberations on the format of the feed we decided that it would be best to split the feed in a number of localised Basic tables and one Extended table. Currently we have only two Basic (US and EN) versions and a fairly straight-forward Extended one. However, the plan is to inlclude more and more column in the Extended one and provide extra localised (Italian, French, Spanish, German, Russian, etc.) tables. When I am saying &#8220;we&#8221; I mean fellow SSAS professionals, which I had the pleasure to discuss this idea (among which <a href="http://sqlblog.com/blogs/marco_russo/">Marco Russo</a>, <a href="http://blog.kejser.org/">Thomas Kejser</a>, <a href="http://www.wfaerber.de/">Willfried Faerber </a>and <a href="http://www.angrykoala.com/_webapp_689/Grant_Paisley">Grant Paisley</a>).</p>
<p>The CodePlex page of the project contains more details about the feed and the tables and also allows for commenting on existing features, as well as requesting new ones. It can be found at <a href="http://datestream.codeplex.com/">http://datestream.codeplex.com/</a>.</p>
<p>The actual feed can be used directly from <a href="https://datamarket.azure.com/dataset/1542c52d-d466-4094-a801-9ef8fd7c6485">https://datamarket.azure.com/dataset/1542c52d-d466-4094-a801-9ef8fd7c6485</a>.</p>
<p>Note the logo &#8211; it was created by Daniele Perilli from<a href="http://www.sqlbi.com"> SQL BI </a>with the assistance provided by Marco Russo. Thanks to them we did not have to resort to my graphic design skills, which definitely is a win for the DataMarket website.</p>
<p>One note - please let me know if the performance you get from the feed is not satisfactory (please remember that once pulled, the feed does not need to be refreshed as the data will remain valid forever). If many people agree that it is too slow I could potentially host it on an alternative location as well. It is possible to download a CSV version from the DataMarket as a workaround, which also allows removing unnecessary date ranges.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/bp-msbi?a=aX2FRRINoWk:RzWGjYo1Zio:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=aX2FRRINoWk:RzWGjYo1Zio:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/bp-msbi?i=aX2FRRINoWk:RzWGjYo1Zio:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/bp-msbi?a=aX2FRRINoWk:RzWGjYo1Zio:YwkR-u9nhCs"><img src="http://feeds.feedburner.com/~ff/bp-msbi?d=YwkR-u9nhCs" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/bp-msbi/~4/aX2FRRINoWk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.bp-msbi.com/2011/10/introducing-project-datestream-codeplex/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		<feedburner:origLink>http://www.bp-msbi.com/2011/10/introducing-project-datestream-codeplex/</feedburner:origLink></item>
	</channel>
</rss>

