<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Analysis Services Team Blog</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/analysisservices/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/analysisservices/feed.xml</link>
    <description>Information, tips, news and announcements about Azure Analysis Services (Azure AS) and SQL Server Analysis Services (SSAS) directly from the product team.</description>
    <lastBuildDate>Fri, 26 Apr 2019 02:49:11 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Future Analysis Services posts on Power BI blog</title>
      <link>https://docs.microsoft.com/archive/blogs/analysisservices/future-analysis-services-posts-on-power-bi-blog</link>
      <pubDate>Fri, 26 Apr 2019 02:29:34 GMT</pubDate>
      <dc:creator><![CDATA[Christian Wade]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/analysisservices/?p=4085</guid>
      <description><![CDATA[The Analysis Services Team Blog has served as the medium for many historic announcements and updates...]]></description>
      <content:encoded><![CDATA[The Analysis Services Team Blog has served as the medium for many historic announcements and updates in Microsoft BI over the past 10 years. Well, Microsoft is moving off MSDN and TechNet blogs, so this will be the last post on this blog site. The site, including all historical posts, will remain online as a read-only archive.

‘So where will new Analysis Services blog posts be published?’ I hear you ask. We have made it clear that Power BI will be a one-stop shop for both enterprise and self-service BI on a single, all-inclusive platform. Power BI will be a superset of Analysis Services, so there is no better place to announce future Analysis Services features than, you guessed it, on the Power BI blog. The Analysis Services engine <span>is at the foundation of Power BI and powers its datasets</span>, so this just feels right.

Please stay tuned to the new Analysis Services category on the Power BI blog for future Azure Analysis Services and SQL Server Analysis Services announcements:

<a href="https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpowerbi.microsoft.com%2Fen-us%2Fblog%2Fcategory%2Fanalysis-services%2F&amp;data=01%7C01%7Cchwade%40microsoft.com%7Ce1e58f94525d4073ddcf08d6c920e0b8%7C72f988bf86f141af91ab2d7cd011db47%7C1&amp;sdata=eMpII1vwphGgf9%2BLRxbO0ABpOea3AdYtRGg8%2Bq1YTxk%3D&amp;reserved=0">https://powerbi.microsoft.com/blog/category/analysis-services/</a>]]></content:encoded>
    </item>
    <item>
      <title>What’s new for SQL Server 2019 Analysis Services CTP 2.4</title>
      <link>https://docs.microsoft.com/archive/blogs/analysisservices/whats-new-for-sql-server-2019-analysis-services-ctp-2-4</link>
      <pubDate>Tue, 26 Mar 2019 02:15:21 GMT</pubDate>
      <dc:creator><![CDATA[Christian Wade]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/analysisservices/?p=4065</guid>
      <description><![CDATA[We are excited to announce the public CTP 2.4 of SQL Server 2019 Analysis Services. This public...]]></description>
      <content:encoded><![CDATA[We are excited to announce the public CTP 2.4 of SQL Server 2019 Analysis Services. This public preview includes the following enhancements for Analysis Services tabular models.
<ul>
 	<li>Many-to-many relationships</li>
 	<li>Memory settings for resource governance</li>
</ul>
<h2>Many-to-many relationships</h2>
Many-to-many (M2M) relationships in CTP 2.4 are based on M2M relationships in Power BI described <a href="https://docs.microsoft.com/power-bi/desktop-many-to-many-relationships">here</a>. M2M relationships in CTP 2.4 do not work with composite models. They allow relationships between tables where both columns are non-unique. A relationship can be defined between a dimension and fact table at a granularity higher than the key column of the dimension. This avoids having to normalize dimension tables and can improve the user experience because the resulting model has a smaller number of tables with logically grouped columns. For example, if Budget is defined at the Product Category level, it is not necessary to normalize the Product dimension into separate tables; one at the granularity of Product and the other at the granularity of Product Category.

<a href="https://msdnshared.blob.core.windows.net/media/2019/03/M2M-relationship.png"><img src="https://msdnshared.blob.core.windows.net/media/2019/03/M2M-relationship.png" alt="" width="549" height="255" class="alignnone size-full wp-image-4075" /></a>
<h3>Tooling</h3>
Many-to-many relationships are currently engine-only features. SSDT support will come before SQL Server 2019 general availability. In the meantime, you can use the fantastic open-source community tool <a href="https://tabulareditor.github.io/">Tabular Editor</a> to create many-to-many relationships. Alternatively, you can use SSAS programming and scripting interfaces such as <a href="https://docs.microsoft.com/bi-reference/tom/introduction-to-the-tabular-object-model-tom-in-analysis-services-amo">TOM</a> and <a href="https://docs.microsoft.com/en-us/bi-reference/tmsl/tabular-model-scripting-language-tmsl-reference">TMSL</a>.
<h3>New 1470 Compatibility Level</h3>
To use many-to-many relationships, existing models must be upgraded to the 1470 compatibility level. 1470 models cannot be deployed to SQL Server 2017 or earlier or downgraded to lower compatibility levels.
<h2>Memory settings for resource governance</h2>
The memory settings described here are already available in Azure Analysis Services. With CTP 2.4, they are now also supported by SQL Server 2019 Analysis Services.
<h3>QueryMemoryLimit</h3>
The <strong>Memory\QueryMemoryLimit</strong> property can be used to limit memory spools built by DAX queries submitted to the model.

Changing this property can be useful in controlling expensive queries that result in significant materialization. If the spooled memory for a query hits the limit, the query is cancelled and an error is returned, reducing the impact on other concurrent users of the system. Currently, MDX queries are not affected. It does not account for other general memory allocations used by the query.

The settable value of 1 to 100 is a percentage. Above that, it’s in bytes. The default value of 0 means not specified and no limit is applied.

You can set this property by using the latest version of SQL Server Management Studio (SSMS), in the Server Properties dialog box. See the Server Memory Properties article for more information.
<h3>DbpropMsmdRequestMemoryLimit</h3>
The <strong>DbpropMsmdRequestMemoryLimit</strong> XMLA property can be used to override the Memory\QueryMemoryLimit server property value for a connection.  The unit of measure is in kilobytes. See the <a href="https://docs.microsoft.com/en-us/sql/analysis-services/instances/connection-string-properties-analysis-services?view=sql-server-2017">Connection String Properties</a> article for more information.
<h3>RowsetSerializationLimit</h3>
The <strong>OLAP\Query\RowsetSerializationLimit</strong> server property limits the number of rows returned in a rowset to clients.

This property, set in the Server Properties dialog box in the latest version of SSMS, applies to both DAX and MDX. It can be used to protect server resources from extensive data export usage. Queries submitted to the server that would exceed the limit are cancelled and an error is returned. The default value is -1, meaning no limit is applied.
<h2>Download Now</h2>
To get started with SQL Server 2019 CTP 2.4, find download instructions on the <a href="https://www.microsoft.com/en-us/sql-server/sql-server-2019">SQL Server 2019 web page</a>. Enjoy!]]></content:encoded>
    </item>
    <item>
      <title>What’s new for SQL Server 2019 Analysis Services CTP 2.3</title>
      <link>https://docs.microsoft.com/archive/blogs/analysisservices/whats-new-for-sql-server-2019-analysis-services-ctp-2-3</link>
      <pubDate>Fri, 01 Mar 2019 10:16:41 GMT</pubDate>
      <dc:creator><![CDATA[Christian Wade]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/analysisservices/?p=4005</guid>
      <description><![CDATA[We find great pleasure in announcing the public CTP 2.3 of SQL Server 2019 Analysis Services. New...]]></description>
      <content:encoded><![CDATA[We find great pleasure in announcing the public CTP 2.3 of SQL Server 2019 Analysis Services. New features detailed here are planned to ship later in Power BI Premium and Azure Analysis Services.
<h2>Calculation groups</h2>
Here is a question for seasoned BI professionals: what is the most powerful feature of SSAS multidimensional? Many would say the ability to define calculated members, typically using scoped cell assignments. Calculated members in multidimensional enable complex calculations by reusing calculation logic. Unfortunately, Analysis Services tabular doesn’t have equivalent functionality. <strong>Correction: it does now!!!</strong>

<strong>Calculation groups</strong> address the issue of proliferation of measures in complex BI models often caused by common calculations like time-intelligence. Enterprise models are reused throughout large organizations, so they grow in scale and complexity. It is not uncommon for Analysis Services models to have hundreds of base measures. Each base measure often requires the same time-intelligence analysis. For example, Sales and Order Count may require:
<ul>
 	<li>Sales MTD, Sales QTD, Sales YTD, Sales PY, Sales YOY%, …</li>
 	<li>Orders MTD, Orders QTD, Orders YTD, Orders PY, Orders YOY%, …</li>
</ul>
As you can see, this can easily explode the number of measures. If a model has 100 base measures and each requires 10 time-intelligence representations, the model ends up with 1,000 measures in total (100*10). This creates the following problems.
<ul>
 	<li>The user experience is overwhelming because must sift through so many measures</li>
 	<li>DAX is difficult to maintain</li>
 	<li>Model metadata is bloated</li>
</ul>
Calculation groups address these issues. They are presented to end-users as a table with a single column. Each value in the column represents a reusable calculation that can be applied to any of the measures where it makes sense. The reusable calculations are called <strong>calculation items</strong>.

By reducing the number of measures, calculation groups present an uncluttered user interface to end users. They are an elegant way to manage DAX business logic. Users simply select calculation groups in the field list to view the calculations in Power BI visuals. There is no need for the end user or modeler to create separate measures.

<a href="https://msdnshared.blob.core.windows.net/media/2019/02/CalcMembers.gif"><img src="https://msdnshared.blob.core.windows.net/media/2019/02/CalcMembers.gif" alt="Calculation groups user experience" width="1146" height="678" class="alignnone size-full wp-image-4015" /></a>

&nbsp;
<h2>Time-intelligence example</h2>
Consider the following calculation group example.
<table border="1" width="50%">
<tbody>
<tr>
<td width="138"><strong>Table</strong></td>
<td width="198">Time Intelligence</td>
</tr>
<tr>
<td width="138"><strong>Column</strong></td>
<td width="198">Time Calculation</td>
</tr>
<tr>
<td width="138"><strong>Precedence</strong></td>
<td width="198">20</td>
</tr>
</tbody>
</table>
&nbsp;
<table width="672" border="1">
<tbody>
<tr>
<td width="114"><strong>Calculation Item</strong></td>
<td width="558"><strong>Expression</strong></td>
</tr>
<tr>
<td width="114">
<pre style="background-color: #ffffff"><span style="color: #ff0000">"Current"</span></pre>
</td>
<td width="558">
<pre style="background-color: #ffffff"><span style="color: #0000ff">SELECTEDMEASURE</span>()</pre>
</td>
</tr>
<tr>
<td width="114">
<pre style="background-color: #ffffff"><span style="color: #ff0000">"MTD"</span></pre>
</td>
<td width="558">
<pre style="background-color: #ffffff"><span style="color: #0000ff">CALCULATE</span>(<span style="color: #0000ff">SELECTEDMEASURE</span>(), <span style="color: #0000ff">DATESMTD</span>(DimDate[Date]))</pre>
</td>
</tr>
<tr>
<td width="114">
<pre style="background-color: #ffffff"><span style="color: #ff0000">"QTD"</span></pre>
</td>
<td width="558">
<pre style="background-color: #ffffff"><span style="color: #0000ff">CALCULATE</span>(<span style="color: #0000ff">SELECTEDMEASURE</span>(), <span style="color: #0000ff">DATESQTD</span>(DimDate[Date]))</pre>
</td>
</tr>
<tr>
<td width="114">
<pre style="background-color: #ffffff"><span style="color: #ff0000">"YTD"</span></pre>
</td>
<td width="558">
<pre style="background-color: #ffffff"><span style="color: #0000ff">CALCULATE</span>(<span style="color: #0000ff">SELECTEDMEASURE</span>(), <span style="color: #0000ff">DATESYTD</span>(DimDate[Date]))</pre>
</td>
</tr>
<tr>
<td width="114">
<pre style="background-color: #ffffff"><span style="color: #ff0000">"PY"</span></pre>
</td>
<td width="558">
<pre style="background-color: #ffffff"><span style="color: #0000ff">CALCULATE</span>(<span style="color: #0000ff">SELECTEDMEASURE</span>(), <span style="color: #0000ff">SAMEPERIODLASTYEAR</span>(DimDate[Date]))</pre>
</td>
</tr>
<tr>
<td width="114">
<pre style="background-color: #ffffff"><span style="color: #ff0000">"PY MTD"</span></pre>
</td>
<td width="558">
<pre style="background-color: #ffffff"><span style="color: #0000ff">CALCULATE</span>(
    <span style="color: #0000ff">SELECTEDMEASURE</span>(),
    <span style="color: #0000ff">SAMEPERIODLASTYEAR</span>(DimDate[Date]),
    'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"MTD"</span>
)</pre>
</td>
</tr>
<tr>
<td width="114">
<pre style="background-color: #ffffff"><span style="color: #ff0000">"PY QTD"</span></pre>
</td>
<td width="558">
<pre style="background-color: #ffffff"><span style="color: #0000ff">CALCULATE</span>(
    <span style="color: #0000ff">SELECTEDMEASURE</span>(),
    <span style="color: #0000ff">SAMEPERIODLASTYEAR</span>(DimDate[Date]),
    'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"QTD"</span>
)</pre>
</td>
</tr>
<tr>
<td width="114">
<pre style="background-color: #ffffff"><span style="color: #ff0000">"PY YTD"</span></pre>
</td>
<td width="558">
<pre style="background-color: #ffffff"><span style="color: #0000ff">CALCULATE</span>(
    <span style="color: #0000ff">SELECTEDMEASURE</span>(),
    <span style="color: #0000ff">SAMEPERIODLASTYEAR</span>(DimDate[Date]),
    'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"YTD"</span>
)</pre>
</td>
</tr>
<tr>
<td width="114">
<pre style="background-color: #ffffff"><span style="color: #ff0000">"YOY"</span></pre>
</td>
<td width="558">
<pre style="background-color: #ffffff"><span style="color: #0000ff">SELECTEDMEASURE</span>() –
<span style="color: #0000ff">CALCULATE</span>(
    <span style="color: #0000ff">SELECTEDMEASURE</span>(),
    'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"PY"</span>
)</pre>
</td>
</tr>
<tr>
<td width="114">
<pre style="background-color: #ffffff"><span style="color: #ff0000">"YOY%"</span></pre>
</td>
<td width="558">
<pre style="background-color: #ffffff"><span style="color: #0000ff">DIVIDE</span>(
    <span style="color: #0000ff">CALCULATE</span>(
        <span style="color: #0000ff">SELECTEDMEASURE</span>(),
        'Time Intelligence'[Time Calculation]=<span style="color: #ff0000">"YOY"</span>
    ),
    <span style="color: #0000ff">CALCULATE</span>(
        <span style="color: #0000ff">SELECTEDMEASURE</span>(),
        'Time Intelligence'[Time Calculation]=<span style="color: #ff0000">"PY"</span>
    ),
)</pre>
</td>
</tr>
</tbody>
</table>
&nbsp;

Here is a DAX query and output. The output shows the calculations applied. For example, QTD for March 2012 is the sum of January, February and March 2012.
<pre><span style="color: #0000ff">EVALUATE</span>
<span style="color: #0000ff">CALCULATETABLE</span> (
    <span style="color: #0000ff">SUMMARIZECOLUMNS</span> (
        DimDate[CalendarYear],
        DimDate[EnglishMonthName],
        <span style="color: #ff0000">"Current"</span>, <span style="color: #0000ff">CALCULATE</span> ( [InternetTotalSales], 'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"Current"</span> ),
        <span style="color: #ff0000">"QTD"</span>,     <span style="color: #0000ff">CALCULATE</span> ( [InternetTotalSales], 'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"QTD"</span> ),
        <span style="color: #ff0000">"YTD"</span>,     <span style="color: #0000ff">CALCULATE</span> ( [InternetTotalSales], 'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"YTD"</span> ),
        <span style="color: #ff0000">"PY"</span>,      <span style="color: #0000ff">CALCULATE</span> ( [InternetTotalSales], 'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"PY"</span> ),
        <span style="color: #ff0000">"PY QTD"</span>,  <span style="color: #0000ff">CALCULATE</span> ( [InternetTotalSales], 'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"PY QTD"</span> ),
        <span style="color: #ff0000">"PY YTD"</span>,  <span style="color: #0000ff">CALCULATE</span> ( [InternetTotalSales], 'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"PY YTD"</span> )
    ),
    DimDate[CalendarYear] IN { 2012, 2013 }
)
</pre>
<a href="https://msdnshared.blob.core.windows.net/media/2019/02/Time-intelligence.png"><img src="https://msdnshared.blob.core.windows.net/media/2019/02/Time-intelligence.png" alt="Time intelligence" width="100%" class="alignnone size-full wp-image-4025" /></a>

&nbsp;
<h2>Sideways recursion</h2>
Some of the calculation items refer to other ones in the same calculation group. This is called “sideways recursion”. For example, <strong>YOY%</strong> (shown below for easy reference) refers to 2 other calculation items, but they are evaluated separately using different calculate statements. Other types of recursion are not supported (see below).
<pre><span style="color: #0000ff">DIVIDE</span>(
    <span style="color: #0000ff">CALCULATE</span>(
        <span style="color: #0000ff">SELECTEDMEASURE</span>(),
        'Time Intelligence'[Time Calculation]=<span style="color: #ff0000">"YOY"</span>
    ),
    <span style="color: #0000ff">CALCULATE</span>(
        <span style="color: #0000ff">SELECTEDMEASURE</span>(),
        'Time Intelligence'[Time Calculation]=<span style="color: #ff0000">"PY"</span>
    ),
)
</pre>
&nbsp;
<h2>Single calculation item in filter context</h2>
Here is the definition of <strong>PY YTD</strong>:
<pre><span style="color: #0000ff">CALCULATE</span>(
    <span style="color: #0000ff">SELECTEDMEASURE</span>(),
    <span style="color: #0000ff">SAMEPERIODLASTYEAR</span>(DimDate[Date]),
    'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"YTD"</span>
)
</pre>
The YTD argument to the CALCULATE() function overrides the filter context to reuse the logic already defined in the YTD calculation item. It is not possible to apply both PY and YTD in a single evaluation. <em>Calculation groups are only applied if a single calculation item from the calculation group is in filter context.</em>

This is illustrated by the following query and output.
<pre><span style="color: #0000ff">EVALUATE</span>
<span style="color: #0000ff">CALCULATETABLE</span> (
    <span style="color: #0000ff">SUMMARIZECOLUMNS</span> (
        DimDate[CalendarYear],
        DimDate[EnglishMonthName],

        <span style="color: #009900">//No time intelligence applied: all calc items in filter context:</span>
        "InternetTotalSales", [InternetTotalSales],

        <span style="color: #009900">//No time intelligence applied: 2 calc items in filter context:</span>
        <span style="color: #ff0000">"PY || YTD"</span>, <span style="color: #0000ff">CALCULATE</span> ( [InternetTotalSales],
            'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"PY"</span> || 'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"YTD"</span>
        ),

        <span style="color: #009900">//YTD applied: exactly 1 calc item in filter context:</span>
        <span style="color: #ff0000">"YTD"</span>, <span style="color: #0000ff">CALCULATE</span> ( [InternetTotalSales], 'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"YTD"</span> )
    ),
    DimDate[CalendarYear] = 2012
)
</pre>
<a href="https://msdnshared.blob.core.windows.net/media/2019/02/Single-calc-item.png"><img src="https://msdnshared.blob.core.windows.net/media/2019/02/Single-calc-item.png" alt="Single-calc-item" width="75%" class="alignnone size-full wp-image-4035" /></a>

A calculation group should be designed so that each calculation item within it presented to the end user only makes sense to be applied <strong>one at a time</strong>. If there is a business requirement to allow the end user to apply more than one calculation item at a time, multiple calculation groups should be used with different precedence.

&nbsp;
<h2>Precedence</h2>
In the same model as the time-intelligence example above, the following calculation group also exists. It contains average calculations that are independent of traditional time intelligence in that they don’t change the date filter context; they just apply average calculations within it.

In this example, a daily average calculation is defined. It is common in oil-and-gas applications to use calculations such as “barrels of oil per day”. Other common business examples include “store sales average” in the retail industry.

Whilst such calculations are calculated independently of time-intelligence calculations, there may well be a requirement to combine them. For example, the end-user might want to see “YTD barrels of oil per day” to view the daily-oil rate from the beginning of the year to the current date. In this scenario, precedence should be set for calculation items.
<table border="1" width="50%">
<tbody>
<tr>
<td width="144"><strong>Table</strong></td>
<td width="192">Averages</td>
</tr>
<tr>
<td width="144"><strong>Column</strong></td>
<td width="192">Average Calculation</td>
</tr>
<tr>
<td width="144"><strong>Precedence</strong></td>
<td width="192">10</td>
</tr>
</tbody>
</table>
&nbsp;
<table width="456">
<tbody>
<tr>
<td width="144"><strong>Calculation Item</strong></td>
<td width="312"><strong>Expression</strong></td>
</tr>
<tr>
<td width="144">
<pre style="background-color: #ffffff"><span style="color: #ff0000">"No Average"</span></pre>
</td>
<td width="312">
<pre style="background-color: #ffffff"><span style="color: #0000ff">SELECTEDMEASURE()</span></pre>
</td>
</tr>
<tr>
<td width="144">
<pre style="background-color: #ffffff"><span style="color: #ff0000">"Daily Average"</span></pre>
</td>
<td width="312">
<pre style="background-color: #ffffff"><span style="color: #0000ff">DIVIDE</span>(<span style="color: #0000ff">SELECTEDMEASURE</span>(), <span style="color: #0000ff">COUNTROWS</span>(DimDate))</pre>
</td>
</tr>
</tbody>
</table>
&nbsp;

Here is a DAX query and output.
<pre><span style="color: #0000ff">EVALUATE</span>
    <span style="color: #0000ff">CALCULATETABLE</span> (
        <span style="color: #0000ff">SUMMARIZECOLUMNS</span> (
        DimDate[CalendarYear],
        DimDate[EnglishMonthName],
        <span style="color: #ff0000">"InternetTotalSales"</span>, <span style="color: #0000ff">CALCULATE</span> (
            [InternetTotalSales],
            'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"Current"</span>,
            'Averages'[Average Calculation] = <span style="color: #ff0000">"No Average"</span>
        ),
        <span style="color: #ff0000">"YTD"</span>, <span style="color: #0000ff">CALCULATE</span> (
            [InternetTotalSales],
            'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"YTD"</span>,
            'Averages'[Average Calculation] = <span style="color: #ff0000">"No Average"</span>
        ),
        <span style="color: #ff0000">"Daily Average"</span>, <span style="color: #0000ff">CALCULATE</span> (
            [InternetTotalSales],
            'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"Current"</span>,
            'Averages'[Average Calculation] = <span style="color: #ff0000">"Daily Average"</span>
        ),
        <span style="color: #ff0000">"YTD Daily Average"</span>, <span style="color: #0000ff">CALCULATE</span> (
            [InternetTotalSales],
            'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"YTD"</span>,
            'Averages'[Average Calculation] = <span style="color: #ff0000">"Daily Average"</span>
        )
    ),
    DimDate[CalendarYear] = 2012
)
</pre>
<a href="https://msdnshared.blob.core.windows.net/media/2019/02/YTD-Daily-Avg.png"><img src="https://msdnshared.blob.core.windows.net/media/2019/02/YTD-Daily-Avg.png" alt="YTD-Daily-Avg" width="90%" class="alignnone size-full wp-image-4045" /></a>

The following table shows how the March 2012 values are calculated.
<table border="1">
<tbody>
<tr>
<td width="162"><strong>Column name</strong></td>
<td width="420"><strong>Calculation</strong></td>
</tr>
<tr>
<td width="162">YTD</td>
<td width="420">Sum of InternetTotalSales for Jan, Feb, Mar 2012

= 495,364 + 506,994 + 373,483</td>
</tr>
<tr>
<td width="162">Daily Average</td>
<td width="420">InternetTotalSales for Mar 2012 divided by # of days in March

= 373,483 / 31</td>
</tr>
<tr>
<td width="162">YTD Daily Average</td>
<td width="420">YTD for Mar 2012 divided by # of days in Jan, Feb and Mar

=  1,375,841 / (31 + 29 + 31)</td>
</tr>
</tbody>
</table>
&nbsp;

For easy reference, here is the definition of the YTD calculation item. It is applied with <strong>Precedence of 20</strong>.
<pre><mark style="background-color: yellow"><span style="color: #0000ff">CALCULATE</span></mark>(<span style="color: #0000ff">SELECTEDMEASURE</span>()<mark style="background-color: yellow">, <span style="color: #0000ff">DATESYTD</span>(DimDate[Date]))</mark>
</pre>
Here is Daily Average. It is applied with <strong>Precedence of 10</strong>.
<pre><mark style="background-color: cyan"><span style="color: #0000ff">DIVIDE</span>(</mark><span style="color: #0000ff">SELECTEDMEASURE</span>()<mark style="background-color: cyan">, <span style="color: #0000ff">COUNTROWS</span>(DimDate))</mark>
</pre>
Since the precedence of the Time Intelligence calculation group is higher than the Averages one, it is applied as broadly as possible. The YTD Daily Average calculation applies YTD to both the numerator <strong>and the denominator</strong> (count of days) of the daily average calculation.

This is equivalent to this calculation:
<pre><mark style="background-color: yellow"><span style="color: #0000ff">CALCULATE</span>(</mark><mark style="background-color: cyan"><span style="color: #0000ff">DIVIDE</span>(<span style="color: #0000ff"></span></mark><span style="color: #0000ff">SELECTEDMEASURE</span>()<mark style="background-color: cyan">, <span style="color: #0000ff">COUNTROWS</span>(DimDate))</mark><mark style="background-color: yellow">, <span style="color: #0000ff">DATESYTD</span>(DimDate[Date]))</mark>
</pre>
<strong>Not this one:</strong>
<pre><mark style="background-color: cyan"><span style="color: #0000ff">DIVIDE</span>(<span style="color: #0000ff"></span></mark><mark style="background-color: yellow"><span style="color: #0000ff">CALCULATE</span>(</mark><span style="color: #0000ff">SELECTEDMEASURE</span>()<mark style="background-color: yellow">, <span style="color: #0000ff">DATESYTD</span>(DimDate[Date]))</mark><mark style="background-color: cyan">, <span style="color: #0000ff">COUNTROWS</span>(DimDate))</mark>
</pre>
&nbsp;
<h2>New DAX functions</h2>
The following new DAX functions have been introduced to work with calculation groups.
<table border="1">
<tbody>
<tr>
<td width="234"><strong>Function name</strong></td>
<td width="390"><strong>Description</strong></td>
</tr>
<tr>
<td width="234">
<pre style="background-color: #ffffff"><span style="color: #0000ff">SELECTEDMEASURE</span>()</pre>
</td>
<td width="390">Returns a reference to the measure currently in context.</td>
</tr>
<tr>
<td width="234">
<pre style="background-color: #ffffff"><span style="color: #0000ff">SELECTEDMEASURENAME</span>()</pre>
</td>
<td width="390">Returns a string containing the name of the measure currently in context.</td>
</tr>
<tr>
<td width="234">
<pre style="background-color: #ffffff"><span style="color: #0000ff">ISSELECTEDMEASURE</span>( M1, M2, … )</pre>
</td>
<td width="390">Returns a Boolean indicating whether the measure currently in context is one of those specified as an argument.</td>
</tr>
</tbody>
</table>
&nbsp;

SELECTEMEASURENAME() or ISSELECTEDMEASURE() can be used to conditionally apply calculation items depending on the measure in context. For example, it probably doesn’t make sense to calculate the daily average of a ratio measure.

With ISSELECTEDMEASURE():
<pre><span style="color: #0000ff">IF</span> (
    <span style="color: #0000ff">ISSELECTEDMEASURE</span> ( [Expense Ratio 1], [Expense Ratio 2] ),
    <span style="color: #0000ff">SELECTEDMEASURE</span> (),
    <span style="color: #0000ff">DIVIDE</span> ( <span style="color: #0000ff">SELECTEDMEASURE</span> (), <span style="color: #0000ff">COUNTROWS</span> ( DimDate ) )
)
</pre>
ISSELECTEDMEASURE() has the advantage of working with formula fix up, so measure-name changes are reflected automatically.

&nbsp;
<h2>Power BI implicit measures</h2>
Calculation groups work with query scope measures, but not inline DAX calculations. This is shown by the following query.
<pre><span style="color: #0000ff">DEFINE</span>
<span style="color: #0000ff">MEASURE</span> FactInternetSales[QueryScope] = <span style="color: #0000ff">SUM</span> ( FactInternetSales[SalesAmount] )
<span style="color: #0000ff">EVALUATE</span>
<span style="color: #0000ff">CALCULATETABLE</span> (
    <span style="color: #0000ff">SUMMARIZECOLUMNS</span> (
        DimDate[CalendarYear],
        DimDate[EnglishMonthName],

        <span style="color: #009900">//YTD applied successfully to model measure:</span>
        <span style="color: #ff0000">"Model Measure"</span>, <span style="color: #0000ff">CALCULATE</span> (
            [InternetTotalSales],
            'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"YTD"</span>
        ),

        <span style="color: #009900">//YTD applied successfully to query scope measure:</span>
        <span style="color: #ff0000">"Query Scope"</span>, <span style="color: #0000ff">CALCULATE</span> (
            [QueryScope],
            'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"YTD"</span>
        ),

        <span style="color: #009900">//YTD not applied to inline calculation:</span>
        <span style="color: #ff0000">"Inline"</span>, <span style="color: #0000ff">CALCULATE</span> (
            <span style="color: #0000ff">SUM</span> ( FactInternetSales[SalesAmount] ),
            'Time Intelligence'[Time Calculation] = <span style="color: #ff0000">"YTD"</span>
        )
    ),
    DimDate[CalendarYear] = 2012
)
</pre>
Power BI implicit measures are created when the end user drags columns onto visuals to view aggregated values without creating an explicit measure. At time of writing, Power BI generates DAX for implicit measures written as inline DAX calculations. This means implicit measures don’t work with calculation groups. To reserve the right to introduce this at a later date, a new model property visible in <a href="https://docs.microsoft.com/bi-reference/tom/introduction-to-the-tabular-object-model-tom-in-analysis-services-amo">TOM</a> has been introduced called <strong>DiscourageImplicitMeasures</strong>. In the current version, it must be set to true to create calculation groups. When set to true, Power BI Desktop in Live Connect mode disables creation of implicit measures.

&nbsp;
<h2>DMV support</h2>
The following <a href="https://docs.microsoft.com/sql/analysis-services/instances/use-dynamic-management-views-dmvs-to-monitor-analysis-services">Dynamic Management Views</a> (DMV) have been introduced for calculation groups.
<ul>
 	<li>TMSCHEMA_CALCULATION_GROUPS</li>
 	<li>TMSCHEMA_CALCULATION_ITEMS</li>
</ul>
&nbsp;
<h2>OLS</h2>
Object-level security (OLS) defined on calculation group tables is not supported in the current release. They can be defined on other tables in the same model. If a calculation item refers to an OLS-secured object, it will return a generic error on evaluation. This is the planned behavior for SSAS 2019.

&nbsp;
<h2>Planned for a forthcoming CTP</h2>
We plan to introduce the following items in a forthcoming SQL Server 2019 CTP.
<ul>
 	<li>MDX query support with calculation groups.</li>
 	<li>RLS is not supported in CTP 2.3. The planned behavior for SSAS 2019 is that you will be able to define RLS on tables in the same model, but not on calculation groups themselves (directly or indirectly).</li>
 	<li>Dynamic format strings. Calculation groups increase the need for dynamic format strings. For example, the YOY% calculation item needs to be displayed as a percentage, while the others should probably inherit the data type of the measure currently in context. We plan to introduce dynamic format strings in an upcoming SQL Server 2019 CTP.</li>
 	<li>ALLSELECTED DAX function support with calculation groups.</li>
 	<li>Detail rows support with calculation groups.</li>
</ul>
&nbsp;
<h2>Limitations of CTP 2.3</h2>
CTP 2.3 of SSAS is still an early build of SSAS 2019. It being released for testing and feedback purposes only, and should not be used by customers in production environments. This applies to models with or without calculation groups.

&nbsp;
<h2>New 1470 Compatibility Level</h2>
To use the new features, existing models must be upgraded to the 1470 compatibility level. 1470 models cannot be deployed to SQL Server 2017 or earlier or downgraded to lower compatibility levels.

&nbsp;
<h2>Differences between calculation groups in tabular and calculated members in multidimensional</h2>
Calculated members in multidimensional are a little more flexible and enable a few scenarios beyond calculation groups, but they come at the cost of added complexity. We feel calculation groups in tabular provide a great deal of the benefits, with significantly less complexity.
<h3>Single calculation-item column</h3>
Calculation groups can only have a single calculation-item column, whereas multidimensional allows multiple hierarchies with calculated members in a single utility dimension.

A DAX filter on a column value implicitly filters the other columns in the same table to the values of that row. Without introducing new semantics and complexity, multiple calculation-item columns in a single table would filter each other implicitly, so are disallowed. If you have a requirement to apply multiple calculation items at a time, use separate calculation groups and the Precedence property shown above.
<h3>Recursion safeguards not required</h3>
MDX supports recursion although there are known performance limitations. Quite often the same query results can be achieved using MDX set-based calculations instead of recursion.

The right-hand side of MDX-script cell assignments to calculated members created by the Business Intelligence Wizard for multidimensional include a reference to the real member from the attribute hierarchy. This is required to safeguard against recursion.

Since DAX doesn’t support recursion, so we don’t need to worry about this for calculation groups. The complexity bar is kept lower. If we ever decide to support recursive DAX in the future, we could perhaps introduce an advanced property to indicate that a DAX object is enabled for recursion, and only then require such safeguards to be in place.
<h3>Calculation items cannot be created on other column types</h3>
Multidimensional allows creation of calculated members on attribute hierarchies that are not part of utility dimensions. For example, a Northwest Region member can be added to the State hierarchy to aggregate Washington, Oregon and Idaho. This is useful for custom-grouping scenarios but can increase the likelihood of solve-order issues.

Calculation items cannot be added to other column types. This keeps semantic definitions simpler. As we enhance calculation groups in the future – for example, if we introduce query-scoped calculation groups – we will take care to learn from the solve-order lessons of the past and strive for consistent behaviors.

&nbsp;
<h2>Tooling</h2>
Calculation groups are currently engine-only features. SSDT support will come before SQL Server 2019 general availability. In the meantime, you can use the fantastic open-source community tool <a href="https://tabulareditor.github.io/">Tabular Editor</a> to author calculation groups. Alternatively, you can use SSAS programming and scripting interfaces such as <a href="https://docs.microsoft.com/bi-reference/tom/introduction-to-the-tabular-object-model-tom-in-analysis-services-amo">TOM</a> and <a href="https://docs.microsoft.com/en-us/bi-reference/tmsl/tabular-model-scripting-language-tmsl-reference">TMSL</a>.

<a href="https://msdnshared.blob.core.windows.net/media/2019/02/Tabular-Editor.png"><img src="https://msdnshared.blob.core.windows.net/media/2019/02/Tabular-Editor.png" alt="Tabular-Editor" width="85%" class="alignnone size-full wp-image-4055" /></a>

&nbsp;
<h2>Pace of delivery</h2>
We think you will agree the AS engine team has been on a tear lately. This is the same team that recently delivered, or is currently working on, the following breakthrough features for Power BI.
<ul>
 	<li>Arguably the biggest scalability feature in the history of the AS engine: <a href="https://docs.microsoft.com/power-bi/desktop-aggregations">aggregations</a></li>
 	<li>Policy-based <a href="https://docs.microsoft.com/power-bi/service-premium-incremental-refresh">incremental refresh</a></li>
 	<li>Opening the XMLA endpoint to bring AS to Power BI</li>
</ul>
Calculation groups is yet another monumental feature delivered in a relatively short period of time. It demonstrates Microsoft’s continued commitment to enterprise BI customers.

&nbsp;
<h2>Download Now</h2>
To try SQL Server 2019 CTP 2.3, find download instructions on the <a href="https://www.microsoft.com/en-us/sql-server/sql-server-2019">SQL Server 2019 web page</a>. Enjoy!

&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>Whitepaper on modeling for AS tabular scalability</title>
      <link>https://docs.microsoft.com/archive/blogs/analysisservices/whitepaper-on-modeling-for-as-tabular-scalability</link>
      <pubDate>Wed, 08 Aug 2018 02:29:10 GMT</pubDate>
      <dc:creator><![CDATA[Christian Wade]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/analysisservices/?p=3995</guid>
      <description><![CDATA[This is a guest post from Daniel Rubiolo of the Power BI Customer Advisory Team (PBI CAT).

To...]]></description>
      <content:encoded><![CDATA[This is a guest post from Daniel Rubiolo of the Power BI Customer Advisory Team (PBI CAT).

To scale Tabular models to very big volumes of data, and with the objective of getting as much of the data as possible into memory so users can consume it in their analyses, we must consider data preparation and modeling best practices to help the engine do its best work.

AS (Analysis Services) Tabular at its core has an in-memory columnar database engine optimized for BI exploratory analytics. It’s highly efficient in encoding and compressing data in memory, supporting custom business logic with calculated columns &amp; measures, enabling high concurrency, and delivering blazing fast responses.

In this whitepaper (<a href="https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2FMicrosoft%2FAnalysis-Services%2Fblob%2Fmaster%2FASTabularScalabilityDesign%2FModeling%2520for%2520AS%2520Scalability.docx&amp;data=02%7C01%7C%7Cae0d545ba4f64c2af26608d5fcd49cdb%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636692912458272233&amp;sdata=CVvV9mnTX8BlM%2FyNn7%2F2tSMcTDFoXCfiGxTr4889ygU%3D&amp;reserved=0">DOCX</a>, <a href="https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2FMicrosoft%2FAnalysis-Services%2Fblob%2Fmaster%2FASTabularScalabilityDesign%2FModeling%2520for%2520AS%2520Scalability.pdf&amp;data=02%7C01%7C%7Cae0d545ba4f64c2af26608d5fcd49cdb%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636692912458282242&amp;sdata=Ym9c32EOlCgXBLxBcywQIOrZqWw9KevD7Ca7pfnNBRE%3D&amp;reserved=0">PDF</a>) we cover a simplified overview of how the Tabular engine works, and several data modeling design best practices that take the most advantage of the engine’s inner workings. This article was written with an Azure Analysis Services example, but equally applies to SQL Server 2017 Analysis Services. (With a few exceptions, these guidelines also apply to Excel’s Power Pivot and Power BI Desktop &amp; Service.)

With a real-world example, we cover recommendations such as:
<ol>
 	<li>Benefits of designing your model as a “dimensional model”, a.k.a. “star schema”.
<ul>
 	<li>Pre-processing your data in this manner will enable the most scale for high data volumes, and deliver the best performance at query time.</li>
</ul>
</li>
 	<li>Steps for optimizing Dimensions:
<ul>
 	<li>Minimize the number of columns.</li>
 	<li>Reduce cardinality (data type conversions).</li>
 	<li>Filter out unused dimension values (unless a business scenario requires them).</li>
 	<li>Integer Surrogate Keys (SK).</li>
 	<li>Ordered by SK (to maximize Value encoding).</li>
 	<li>Hint for VALUE encoding on numeric columns.</li>
 	<li>Hint for disabling hierarchies on SKs.</li>
</ul>
</li>
 	<li>Steps for optimizing Facts:
<ul>
 	<li>Handle early arriving facts. <em>[Facts without corresponding dimension records.]</em></li>
 	<li>Replace dimension IDs with their surrogate keys.</li>
 	<li>Reduce cardinality (data type conversions).</li>
 	<li>Consider moving calculations to the source (to use in compression evaluations).</li>
 	<li>Ordered by less diverse SKs first (to maximize compression).</li>
 	<li>Increased Tabular sample size for deciding Encoding, by considering segments and partitions.</li>
 	<li>Hint for VALUE encoding on numeric columns.</li>
 	<li>Hint for disabling hierarchies.</li>
</ul>
</li>
</ol>
AS Tabular provides very high flexibility in what models you can build. The guidelines in this article will help you maximize the capabilities you provide with your solutions. We hope you find it useful!]]></content:encoded>
    </item>
    <item>
      <title>New memory options for Analysis Services</title>
      <link>https://docs.microsoft.com/archive/blogs/analysisservices/new-memory-options-for-analysis-services</link>
      <pubDate>Fri, 08 Jun 2018 19:34:58 GMT</pubDate>
      <dc:creator><![CDATA[Christian Wade]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/analysisservices/?p=3955</guid>
      <description><![CDATA[We’re happy to introduce some new memory settings for Azure Analysis Services and SQL Server...]]></description>
      <content:encoded><![CDATA[We’re happy to introduce some new memory settings for Azure Analysis Services and SQL Server Analysis Services tabular models. These new settings are primarily for resource governance, and in some cases can speed up data refresh.
<h2>IsAvailableInMdx</h2>
The <strong>IsAvailableInMdx</strong> column property is available in Azure Analysis Services and SQL Server Analysis Services 2017 CU7.

It prevents building attribute hierarchies, reducing memory consumption. This means the column is not available for group-by queries to MDX clients like Excel. Fact (transactional) table columns often don’t need to be grouped and are often the ones that use up the most memory.

This property can also improve performance of refresh operations; particularly for tables with lots of partitions. Building attribute hierarchies can be very expensive because they’re built over all the data in the table.

Currently, this property is not yet exposed in SSDT. It must be set in the JSON-based metadata by using <u><a href="https://docs.microsoft.com/sql/analysis-services/tabular-model-scripting-language-tmsl-reference">Tabular Model Scripting Language</a></u> (TMSL) or the <u><a href="https://docs.microsoft.com/sql/analysis-services/tabular-model-programming-compatibility-level-1200/introduction-to-the-tabular-object-model-tom-in-analysis-services-amo">Tabular Object Model</a></u> (TOM). This property is specified as a Boolean.

The following snippet of JSON-based metadata from the Model.bim file disables attribute hierarchies for the Sales Amount column:
<pre>  {
    <span style="color: #2e75b6">"name"</span>: <span style="color: #800000">"Sales Amount"</span>,
    <span style="color: #2e75b6">"dataType"</span>: <span style="color: #800000">"decimal"</span>,
    <span style="color: #2e75b6">"sourceColumn"</span>: <span style="color: #800000">"SalesAmount"</span>,
    <b><span style="color: #2e75b6">"isAvailableInMdx"</span>: <span style="color: #800000">false</span></b>
  }
</pre>
<h2>QueryMemoryLimit</h2>
The <strong>Memory\QueryMemoryLimit</strong> property can be used to limit memory spools built by DAX queries submitted to the model. Currently, this property is only available in Azure Analysis Services.

Changing this property can be useful in controlling expensive queries that result in significant materialization. If the spooled memory for a query hits the limit, the query is cancelled and an error is returned, reducing the impact on other concurrent users of the system. Currently, MDX queries are not affected. It does not account for other general memory allocations used by the query.

The settable value of 1 to 100 is a percentage. Above that, it’s in bytes. The default value of 0 means not specified and no limit is applied.

You can set this property by using the <a href="https://docs.microsoft.com/sql/ssms/download-sql-server-management-studio-ssms">latest version</a> of SQL Server Management Studio (SSMS), in the Server Properties dialog box. See the <span><a href="https://docs.microsoft.com/en-us/sql/analysis-services/server-properties/memory-properties">Server Memory Properties</a></span> article for more information.

<a href="https://msdnshared.blob.core.windows.net/media/2018/06/QueryMemoryLimit.png"><img src="https://msdnshared.blob.core.windows.net/media/2018/06/QueryMemoryLimit.png" alt="QueryMemoryLimit" width="692" height="626" class="alignnone size-full wp-image-3965" /></a>
<h2>DbpropMsmdRequestMemoryLimit</h2>
The <strong>DbpropMsmdRequestMemoryLimit</strong> XMLA property can be used to override the Memory\QueryMemoryLimit server property value for a connection. Currently, this property is only available in Azure Analysis Services.  The unit of measure is in kilobytes. See the <span><a href="https://docs.microsoft.com/sql/analysis-services/instances/connection-string-properties-analysis-services">Connection String Properties</a></span> article for more information.
<h2>RowsetSerializationLimit</h2>
The <strong>OLAP\Query\RowsetSerializationLimit</strong> server property limits the number of rows returned in a rowset to clients. Currently, this property is only available in Azure Analysis Services.

This property, set in the Server Properties dialog box in the latest version of SSMS, applies to both DAX and MDX. It can be used to protect server resources from extensive data export usage. Queries submitted to the server that would exceed the limit are cancelled and an error is returned. The default value is -1, meaning no limit is applied.]]></content:encoded>
    </item>
    <item>
      <title>Automation of Analysis Services with NuGet packages</title>
      <link>https://docs.microsoft.com/archive/blogs/analysisservices/automation-of-analysis-services-with-nuget-packages</link>
      <pubDate>Sat, 10 Feb 2018 03:33:43 GMT</pubDate>
      <dc:creator><![CDATA[Christian Wade]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/analysisservices/?p=3926</guid>
      <description><![CDATA[We are pleased to announce that the Analysis Services Management Objects (AMO) and ADOMD client...]]></description>
      <content:encoded><![CDATA[We are pleased to announce that the Analysis Services Management Objects (AMO) and ADOMD client libraries are now available from NuGet.org! This simplifies the development and management of automation tasks for Azure Analysis Services and SQL Server Analysis Services.

NuGet provides benefits including the following.
<ul>
 	<li><a href="https://docs.microsoft.com/azure/azure-functions/functions-overview">Azure Functions</a> require less manual intervention to work with Azure Analysis Services.</li>
 	<li>ISVs and developers of community tools for Analysis Services such as <a href="https://daxstudio.org/">DAX Studio</a>, <a href="https://tabulareditor.github.io/">Tabular Editor</a>, <a href="https://bism-normalizer.com/">BISM Normalizer</a> and others will benefit from simplified deployment and reliable (non-GAC) references.</li>
</ul>
Visit this <a href="https://docs.microsoft.com/nuget/">site</a> for information on what NuGet is for and how to use it.
<h3>AMO</h3>
<a href="https://www.nuget.org/packages/Microsoft.AnalysisServices.retail.amd64/">https://www.nuget.org/packages/Microsoft.AnalysisServices.retail.amd64/</a>

AMO contains the object libraries to create and manage both Analysis Services multidimensional and tabular models. The object library for tabular is called the Tabular Object Model (TOM). See <a href="https://docs.microsoft.com/en-us/sql/analysis-services/tabular-model-programming-compatibility-level-1200/introduction-to-the-tabular-object-model-tom-in-analysis-services-amo">here</a> for more information.
<h3>ADOMD</h3>
<a href="https://www.nuget.org/packages/Microsoft.AnalysisServices.AdomdClient.retail.amd64/">https://www.nuget.org/packages/Microsoft.AnalysisServices.AdomdClient.retail.amd64/</a>

ADOMD is used primarily for development of client tools that submit MDX or DAX queries to Analysis Services for user analysis. See <a href="https://docs.microsoft.com/sql/analysis-services/multidimensional-models/adomd-net/developing-with-adomd-net">here</a> for more information.
<h3>MSI installer</h3>
We recommend that all developers who use these libraries migrate to NuGet references instead of using the MSI installer. The MSI installer for AMO and ADOMD are still available <a href="https://docs.microsoft.com/en-us/azure/analysis-services/analysis-services-data-providers">here</a>. Starting from MAJOR version 15 to the foreseeable future, we plan to release the client libraries as both NuGet packages and the MSI installer. In the long term, we want to retire the MSI installer.
<h3>NuGet versioning</h3>
NuGet package assemblies AssemblyVersion will follow <a href="https://semver.org/">semantic versioning</a>: MAJOR.MINOR.PATCH. This ensures NuGet references load the expected version even if there is a different version in the GAC (resulting from MSI install). We will increment at least the PATCH for each public release. AMO and ADOMD versions will be kept in sync.
<h3>MSI versioning</h3>
The MSI version will continue to use a versioning scheme for AssemblyVersion like 15.0.0.0 (MAJOR version only). The MSI installs assemblies to the GAC and overrides previous MSI installations for the same MAJOR version. This versioning scheme ensures new releases do not affect NuGet references. It also ensures a single entry in Add/Remove Programs for each installation of a MAJOR version.
<h3>Windows Explorer file properties</h3>
The AssemblyFileVersion (visible in Windows Explorer as the File Version) will be the full version for both MSI and NuGet (e.g. 15.0.1.333).

The AssemblyInformationalVersion (visible in Windows Explorer as the Product Version) will be the semantic version for both MSI and NuGet (e.g. 15.0.1.0).

For anyone who has done significant development with Analysis Services, we hope you enjoy the NuGet experience for Analysis Services!]]></content:encoded>
    </item>
    <item>
      <title>Asynchronous Refresh with the REST API for Azure Analysis Services</title>
      <link>https://docs.microsoft.com/archive/blogs/analysisservices/asynchronous-refresh-with-the-rest-api-for-azure-analysis-services</link>
      <pubDate>Wed, 20 Dec 2017 22:03:15 GMT</pubDate>
      <dc:creator><![CDATA[Christian Wade]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/analysisservices/?p=3875</guid>
      <description><![CDATA[We are pleased to introduce the REST API for Azure Analysis Services. Using any programming language...]]></description>
      <content:encoded><![CDATA[We are pleased to introduce the REST API for Azure Analysis Services. Using any programming language that supports REST calls, you can now perform asynchronous data-refresh operations. This includes synchronization of read-only replicas for query scale out.

Data-refresh operations can take some time depending on various factors including data volume and level of optimization using partitions, etc. These operations have traditionally been invoked with existing methods such as using <a href="https://docs.microsoft.com/en-us/sql/analysis-services/tabular-model-programming-compatibility-level-1200/introduction-to-the-tabular-object-model-tom-in-analysis-services-amo">TOM</a> (Tabular Object Model), PowerShell <a href="https://docs.microsoft.com/en-us/sql/analysis-services/powershell/analysis-services-powershell-reference">cmdlets</a> for Analysis Services, or <a href="https://docs.microsoft.com/en-us/sql/analysis-services/tabular-model-scripting-language-tmsl-reference">TMSL</a> (Tabular Model Scripting Language). The traditional methods may require long-running HTTP connections. A lot of work has been done to ensure the stability of these methods, but given the nature of HTTP, it may be more reliable to avoid long-running HTTP connections from client applications.

The REST API for Azure Analysis Services enables data-refresh operations to be carried out asynchronously. It therefore does not require long-running HTTP connections from client applications. Additionally, there are other built-in features for reliability such as auto retries and batched commits.
<h2>Base URL</h2>
The base URL follows this format:
<p style="padding-left: 30px">https://&lt;rollout&gt;.asazure.windows.net/servers/&lt;serverName&gt;/models/&lt;resource&gt;/</p>
For example, consider a model named AdventureWorks, on a server named myserver, located in the West US Azure region. The server name is:
<p style="padding-left: 30px">asazure://westus.asazure.windows.net/myserver</p>
The base URL is:
<p style="padding-left: 30px"><a href="https://westus.asazure.windows.net/servers/myserver/models/AdventureWorks/">https://westus.asazure.windows.net/servers/myserver/models/AdventureWorks/</a></p>
Using the base URL, resources and operations can be appended based on the following diagram:

<a href="https://msdnshared.blob.core.windows.net/media/2017/12/Objects.png"><img src="https://msdnshared.blob.core.windows.net/media/2017/12/Objects.png" alt="REST API Diagram" width="1860" height="311" class="size-full wp-image-3885" /></a>
<ul>
 	<li>Anything that ends in "s" is a collection.</li>
 	<li>Anything that ends with "()" is a function.</li>
 	<li>Anything else is a resource/object.</li>
</ul>
For example, you can use the POST verb on the Refreshes collection to perform a refresh operation:
<p style="padding-left: 30px"><a href="https://westus.asazure.windows.net/servers/myserver/models/AdventureWorks/refreshes">https://westus.asazure.windows.net/servers/myserver/models/AdventureWorks/refreshes</a></p>

<h2>Authentication</h2>
All calls must be authenticated with a valid Azure Active Directory (OAuth 2) token in the Authorization header and must meet the following requirements:
<ul>
 	<li>The token must be either a user token or an application service principal.</li>
 	<li>The user or application must have sufficient permissions on the server or model to make the requested call. The permission level is determined by roles within the model or the admin group on the server.</li>
 	<li>The token must have the correct audience set to: "https://*.asazure.windows.net".</li>
</ul>
<h2>POST /refreshes</h2>
To perform a refresh operation, use the POST verb on the /refreshes collection to add a new refresh item to the collection. The Location header in the response includes the refresh ID. The client application can disconnect and check the status later if required because it is asynchronous.

Only one refresh operation is accepted at a time for a model. If there is a current running refresh operation and another is submitted, the 409 Conflict HTTP status code will be returned.

The body may, for example, resemble the following:
<pre>{
    "Type": "Full",
    "CommitMode": "transactional",
    "MaxParallelism": 2,
    "RetryCount": 2,
    "Objects": [
        {
            "table": "DimCustomer",
            "partition": "DimCustomer"
        },
        {
            "table": "DimDate"
        }
    ]
}</pre>
Here's a list of parameters:
<table width="642">
<tbody>
<tr>
<td width="119"><strong>Name</strong></td>
<td width="56"><strong>Type</strong></td>
<td width="293"><strong>Description</strong></td>
<td width="78"><strong>Required?</strong></td>
<td width="96"><strong>Default</strong></td>
</tr>
<tr>
<td width="119">Type</td>
<td width="56">Enum</td>
<td width="293">The type of processing to perform. The types are aligned with the TMSL <a href="https://docs.microsoft.com/en-us/sql/analysis-services/tabular-models-scripting-language-commands/refresh-command-tmsl">refresh command</a> types: full, clearValues, calculate, dataOnly, automatic, add and defragment.</td>
<td width="78">False</td>
<td width="96">automatic</td>
</tr>
<tr>
<td width="119">CommitMode</td>
<td width="56">Enum</td>
<td width="293">Determines if objects will be committed in batches or only when complete.

Modes include: default, transactional, partialBatch.</td>
<td width="78">False</td>
<td width="96">transactional</td>
</tr>
<tr>
<td width="119">MaxParallelism</td>
<td width="56">int</td>
<td width="293">This value determines the maximum number of threads on which to run processing commands in parallel. This aligned with the MaxParallelism property that can be set in the TMSL <a href="https://docs.microsoft.com/en-us/sql/analysis-services/tabular-models-scripting-language-commands/sequence-command-tmsl">Sequence command</a> or using other methods.</td>
<td width="78">False</td>
<td width="96">10</td>
</tr>
<tr>
<td width="119">RetryCount</td>
<td width="56">int</td>
<td width="293">Indicates the number of times the operation will retry before failing.</td>
<td width="78">False</td>
<td width="96">0</td>
</tr>
<tr>
<td width="119">Objects</td>
<td width="56">Array[]</td>
<td width="293">An array of objects to be processed. Each object includes:

"table" when processing the entire table or "table" and "partition" when processing a partition.

If no objects are specified, the whole model is refreshed.</td>
<td width="78">False</td>
<td width="96">Process the entire model</td>
</tr>
</tbody>
</table>
CommitMode equal to partialBatch can be used when doing an initial load of a large dataset that may take hours. At time of writing, the batch size is the MaxParallelism value, but this may change. If the refresh operation fails after successfully committing one or more batches, the successfully committed batches will remain committed (it will not roll back successfully committed batches).
<h2>GET /refreshes/&lt;refreshId&gt;</h2>
To check the status of a refresh operation, use the GET verb on the refresh ID. Here's an example of the response body. The status field returns “inProgress” if the operation is in progress.
<pre>{
    "startTime": "2017-12-07T02:06:57.1838734Z",
    "endTime": "2017-12-07T02:07:00.4929675Z",
    "type": "full",
    "status": "succeeded",
    "currentRefreshType": "full",
    "objects": [
        {
            "table": "DimCustomer",
            "partition": "DimCustomer",
            "status": "succeeded"
        },
        {
            "table": "DimDate",
            "partition": "DimDate",
            "status": "succeeded"
        }
    ]
}
</pre>
<h2>GET /refreshes</h2>
To retrieve a list of historical refresh operations for a model, use the GET verb on the /refreshes collection. Here is an example of the response body. At time of writing, the last 30 days of refresh operations are stored and returned, but this is subject to change.
<pre>[
    {
        "refreshId": "1344a272-7893-4afa-a4b3-3fb87222fdac",
        "startTime": "2017-12-09T01:58:04.76",
        "endTime": "2017-12-09T01:58:12.607",
        "status": "succeeded"
    },
    {
        "refreshId": "474fc5a0-3d69-4c5d-adb4-8a846fa5580b",
        "startTime": "2017-12-07T02:05:48.32",
        "endTime": "2017-12-07T02:05:54.913",
        "status": "succeeded"
    }
]</pre>
<h2>DELETE /refreshes/&lt;refreshId&gt;</h2>
To cancel an in-progress refresh operation, use the DELETE verb on the refresh ID.
<h2>POST /sync</h2>
Having performed refresh operations, it may be necessary to synchronize the new data with replicas for query scale out. To perform a synchronize operation for a model, use the POST verb on the /sync function. The Location header in the response includes the sync operation ID.
<h2>GET /sync?operationId=&lt;operationId&gt;</h2>
To check the status of a sync operation, use the GET verb passing the operation ID as a parameter. Here's an example of the response body:
<pre>{
    "operationId": "cd5e16c6-6d4e-4347-86a0-762bdf5b4875",
    "database": "AdventureWorks2",
    "UpdatedAt": "2017-12-09T02:44:26.18",
    "StartedAt": "2017-12-09T02:44:20.743",
    "syncstate": 2,
    "details": null
}</pre>
Possible values for syncstate include the following:
<ul>
 	<li>0: Replicating. Database files are being replicated to a target folder.</li>
 	<li>1: Rehydrating. The database is being rehydrated on read-only server instance(s).</li>
 	<li>2: Completed. The sync operation completed successfully.</li>
 	<li>3: Failed. The sync operation failed.</li>
 	<li>4: Finalizing. The sync operation has completed but is performing clean up steps.</li>
</ul>
<h2>Code sample</h2>
Here's a C# code sample to get you started:

<a href="https://github.com/Microsoft/Analysis-Services/tree/master/RestApiSample">https://github.com/Microsoft/Analysis-Services/tree/master/RestApiSample</a>

To use the code sample, first do the following:
<ol>
 	<li>Clone or download the repo. Open the RestApiSample solution.</li>
 	<li>Find the line “client.BaseAddress = …” and provide your base URL (see above).</li>
</ol>
The code sample can use the following forms of authentication:
<ul>
 	<li>Interactive login or username/password</li>
 	<li>Service principal</li>
</ul>
<h3>Interactive login or username/password</h3>
This form of authentication requires an Azure application be set up with the necessary API permissions assigned. This section describes how to set up the application using the Azure portal.
<ol>
 	<li>Select the Azure Active Directory section, click App registrations, and then New application registration.</li>
</ol>
<p style="padding-left: 30px"><a href="https://msdnshared.blob.core.windows.net/media/2017/12/New-App.png"><img src="https://msdnshared.blob.core.windows.net/media/2017/12/New-App.png" alt="New app registration" width="973" height="302" class="alignnone size-full wp-image-3895" /></a></p>

<ol start="2">
 	<li>In the Create blade, enter a meaningful name, select Native application type, and then enter “urn:ietf:wg:oauth:2.0:oob” for the Redirect URI. Then click the Create button.</li>
</ol>
<p style="padding-left: 30px"><a href="https://msdnshared.blob.core.windows.net/media/2017/12/Create-App.png"><img src="https://msdnshared.blob.core.windows.net/media/2017/12/Create-App.png" alt="Create-App" width="973" height="397" class="alignnone size-full wp-image-3905" /></a></p>

<ol start="3">
 	<li>Select your app from the list and take note of the Application ID.</li>
</ol>
<p style="padding-left: 30px"><a href="https://msdnshared.blob.core.windows.net/media/2017/12/App-ID.png"><img src="https://msdnshared.blob.core.windows.net/media/2017/12/App-ID.png" alt="App-ID" width="974" height="338" class="alignnone size-full wp-image-3906" /></a></p>

<ol start="4">
 	<li>In the Settings section for your app, click Required permissions, and then click Add.</li>
</ol>
<p style="padding-left: 30px"><a href="https://msdnshared.blob.core.windows.net/media/2017/12/Required-Permissions.png"><img src="https://msdnshared.blob.core.windows.net/media/2017/12/Required-Permissions.png" alt="Required-Permissions" width="973" height="330" class="alignnone size-full wp-image-3915" /></a></p>

<ol start="5">
 	<li>In Select an API, type “SQL Server Analysis Services” into the search box. Then select “Azure Analysis Services (SQL Server Analysis Services Azure)”.</li>
</ol>
<p style="padding-left: 30px"><a href="https://msdnshared.blob.core.windows.net/media/2017/12/API-Permissions.png"><img src="https://msdnshared.blob.core.windows.net/media/2017/12/API-Permissions.png" alt="API-Permissions" width="974" height="339" class="alignnone size-full wp-image-3916" /></a></p>

<ol start="6">
 	<li>Select Read and Write all Models and then click the Select button. Then click Done to add the permissions. It may take a few minutes to propagate.</li>
</ol>
<p style="padding-left: 30px"><a href="https://msdnshared.blob.core.windows.net/media/2017/12/API-Permissions-2.png"><img src="https://msdnshared.blob.core.windows.net/media/2017/12/API-Permissions-2.png" alt="API-Permissions" width="973" height="342" class="alignnone size-full wp-image-3925" /></a></p>

<ol start="7">
 	<li>In the code sample, find the method UpdateToken(). Observe the contents of this method.</li>
 	<li>Find the line “string clientID = …” and enter the application ID you previously recorded.</li>
 	<li>Run the sample.</li>
</ol>
<h3>Service principal</h3>
Please see the <a href="https://azure.microsoft.com/blog/automation-of-azure-analysis-services-with-service-principals-and-powershell/">Automation of Azure Analysis Services with Service Principals and PowerShell</a> blog post for how to set up a service principal and assign the necessary permissions in Azure Analysis Services. Having done this, the following additional steps are required:
<ol>
 	<li>Find the line “string authority = …” and enter your organization’s tenant ID in place of “common”. See code comments for further info.</li>
 	<li>Comment/uncomment so the ClientCredential class is used to instantiate the cred object. Ensure the &lt;App ID&gt; and &lt;App Key&gt; values are accessed in a secure way or use certificate-based authentication for service principals.</li>
 	<li>Run the sample.</li>
</ol>]]></content:encoded>
    </item>
    <item>
      <title>Using Legacy Data Sources in Tabular 1400</title>
      <link>https://docs.microsoft.com/archive/blogs/analysisservices/using-legacy-data-sources-in-tabular-1400</link>
      <pubDate>Tue, 12 Sep 2017 20:47:47 GMT</pubDate>
      <dc:creator><![CDATA[KayUnkroth]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/analysisservices/?p=3805</guid>
      <description><![CDATA[The modern Get Data experience in Tabular 1400 brings interesting new data discovery and...]]></description>
      <content:encoded><![CDATA[The modern Get Data experience in Tabular 1400 brings interesting new data discovery and transformation capabilities to Analysis Services. However, not every BI professional is equally excited. Especially those who prefer to build their models exclusively on top of SQL Server databases or data warehouses and appreciate the steadiness of tried and proven T-SQL queries over fast SQL OLE DB provider connections might not see a need for mashups. If you belong to this group of BI professionals, there is good news: Tabular 1400 fully supports provider data sources and native query partitions. The modern Get Data experience is optional.
<h2>Upgrading from 1200 to 1400</h2>
Perhaps the easiest way to create a Tabular 1400 model with provider data sources and native query partitions is to upgrade an existing 1200 model to the 1400 compatibility level. If you used Windiff or a similar tool to compare the Model.bim file in your Tabular project before and after the upgrade, you will find that not much was changed. In fact, the only change concerns the compatibilityLevel parameter, which the upgrade logic sets to a value of 1400, as the following screenshot reveals.

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/Windiff-Tabular-Models.png"><img width="879" height="500" class="alignnone size-large wp-image-3866" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/Windiff-Tabular-Models-1024x583.png" /></a>

At the 1400 compatibility level, regardless of the data sources and table partitions, you can use any advanced modeling feature, such as detail rows expressions and object-level security. There are no dependencies on structured data sources or M partitions using the Mashup engine. Legacy provider data sources and native query partitions work just as well. They bypass the Mashup engine. It's just two different code paths to get the data.
<h2>Provider data sources versus structured data sources</h2>
Provider data sources get their name from the fact that they define the parameters for a data provider in the form of a connection string that the Analysis Services engine then uses to connect to the data source. They are sometimes referred to as legacy data sources because they are typically used in 1200 and earlier compatibility levels to define the data source details.

Structured data sources, on the other hand, get their name from the fact that they define the connection details in structured JSON property bags. They are sometimes referred to as modern or Power Query/M-based data sources because they correspond to Power Query/M-based data access functions, as explained in more detail in <a href="https://blogs.msdn.microsoft.com/analysisservices/2017/08/28/supporting-advanced-data-access-scenarios-in-tabular-1400-models/">Supporting Advanced Data Access Scenarios in Tabular 1400 Models</a>.

At a first glance, provider data sources have an advantage over structured data sources because they provide full control over the connection string. You can specify any advanced parameter that the provider supports. In contrast, structured data sources only support the address parameters and options that their corresponding data access functions support. This is usually sufficient, however. Note that provider data sources also have disadvantages, as explained in the next section.

A small sample application can help to illustrate the metadata differences between provider data sources and structured data sources. Both can be added to a Tabular 1400 model using Tabular Object Model (TOM) or the Tabular Model Scripting Language (TMSL).

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/PDS-vs-SDS.png"><img width="879" height="588" class="alignnone size-large wp-image-3835" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/PDS-vs-SDS-1024x685.png" /></a>

Note that Analysis Services always invokes the Mashup engine when using structured data sources to get the data. It might or might not for provider data sources. The choice depends on the table partitions on top of the data source, as the next section explains.
<h2>Query partitions versus M partitions</h2>
Just as there are multiple types of data source definitions in Tabular 1400, there are also multiple partition source types to import data into a table. Specifically, you can define a partition by using a QueryPartitionSource or an MPartitionSource, as in the following TOM code sample.

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/QP-vs-MP.png"><img width="879" height="588" class="alignnone size-large wp-image-3855" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/QP-vs-MP-1024x685.png" /></a>

As illustrated, you can mix query partitions with M partitions even on a single table. The only requirement is that all partition sources must return the same set of source columns, mapped to table columns at the Tabular metadata layer. In the example above, both partitions use the same data source and import the same data, so you end up with duplicate rows. This is normally not what you want, but in this concrete example, the duplicated rows help to illustrate that Analyses Services could indeed process both partition sources successfully, as in the following screenshot.

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/QP-vs-MP-in-SSDT.png"><img width="879" height="734" class="alignnone size-large wp-image-3845" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/QP-vs-MP-in-SSDT-1024x855.png" /></a>

The Model.bim file reveals that the M and query partition sources reference a structured data source, but they could also reference a provider data source as in the screenshot below the following table summarizing the possible combinations. In short, you can mix and match to your heart's content.
<table width="660">
<tbody>
<tr>
<td width="29"><strong> </strong></td>
<td width="161"><strong>Data Source</strong></td>
<td width="157"><strong>Partition Source</strong></td>
<td width="313"><strong>Comments</strong></td>
</tr>
<tr>
<td width="29">1</td>
<td width="161">Provider Data Source</td>
<td width="157">Query Partition Source</td>
<td width="313">The AS engine uses the cartridge-based connectivity stack to access the data source.</td>
</tr>
<tr>
<td width="29">2</td>
<td width="161">Provider Data Source</td>
<td width="157">M Partition Source</td>
<td width="313">The AS engine translates the provider data source into a generic structured data source and then uses the Mashup engine to import the data.</td>
</tr>
<tr>
<td width="29">3</td>
<td width="161">Structured Data Source</td>
<td width="157">Query Partition Source</td>
<td width="313">The AS engine wraps the native query on the partition source into an M expression and then uses the Mashup engine to import the data.</td>
</tr>
<tr>
<td width="29">4</td>
<td width="161">Structured Data Source</td>
<td width="157">M Partition Source</td>
<td width="313">The AS engine uses the Mashup engine to import the data.</td>
</tr>
</tbody>
</table>
&nbsp;

The scenarios 1 and 4 are straightforward. Scenario 3 is practically equivalent to scenario 4. Instead of creating a query partition source with a native query and having the AS engine convert this into an M expression, you could define an M partition source in the first place and use the Value.NativeQuery function to specify the native query, as the following screenshot demonstrates. Of course, this only works for connectors that support native source queries and the Value.NativeQuery function.

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/ValueNativeQuery.png"><img width="1019" height="776" class="alignnone size-full wp-image-3865" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/ValueNativeQuery.png" /></a>

Scenario 2, "M partition on top of a provider data source" is more complex than the others because it involves converting the provider data source into a generic structured data source. In other words, a provider data source pointing to a SQL Server database is not equivalent to a structured SQL Server data source because the AS engine does not convert this provider data source into a structured SQL Server data source. Instead, it converts it into a generic structured OLE DB, ODBC, or ADO.NET data source depending on the data provider that the provider data source referenced. For SQL Server connections, this is usually an OLE DB data source.

The fact that provider data sources are converted into generic structured data sources has important implications. For starters, M expressions on top of a generic data source differ from M expressions on top of a specific structured data source. For example, as the next screenshot highlights, an M expression over an OLE DB data source requires additional navigation steps to get to the desired table. You cannot simply take an M expression based on a structured SQL Server data source and put it on top of a generic OLE DB provider data source. If you tried, you would most likely get an error that the expression references an unknown variable or function.

Moreover, the Mashup engine cannot apply its query optimizations for SQL Server when using a generic OLE DB data source, so M expressions on top of generic provider data sources cannot be processed as efficiently as M expressions on top of specific structured data sources. For this reason, it is better to add a new structured data source to the model for any new M expression-based table partitions than to use an existing provider data source. Provider data sources and structured data sources can coexist in the same Tabular model.

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/QP-vs-MP-in-SSDT-over-PDS.png"><img width="879" height="703" class="alignnone size-large wp-image-3836" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/QP-vs-MP-in-SSDT-over-PDS-1024x819.png" /></a>

In Tabular 1400, the main purpose of a provider data source is backward compatibility with Tabular 1200 so that the processing behavior of your models does not change just because you upgraded to 1400 and so that any ETL logic programmatically generating data sources and table partitions continues to work seamlessly. As mentioned, query partitions on top of a provider data source bypass the Mashup engine. However, the processing performance is not necessarily inferior with a structured data source thanks to a number of engine optimizations. This might seem counterintuitive, but it is a good idea to double-check the processing performance in your environment. The Microsoft SQL Server Native Client OLE DB Provider is indeed performing faster than the Mashup engine. In very large Tabular 1400 models connecting to SQL Server databases, it can therefore be advantageous to use a provider data source and query partitions.
<h2>Data sources and partitions in SSDT Tabular</h2>
With TMSL and TOM, you can create data sources and table partitions in any combination, but this is not the case in SSDT Tabular. By default, SSDT creates structured data sources, and when you right-click a structured data source in Tabular Model Explorer and select Import New Tables, you launch the modern Get Data UI. Among other things, the default behavior helps to provide a consistent user interface and avoids confusion. You don't need to weigh the pros and cons of provider versus structured and you don't need to select a different partition source type and work with a different UI just because you wanted to write a native query. As explained in the previous section, an M expression using Value.NativeQuery is equivalent to a query partition over a structured data source.

Only if a model contains provider data sources already, say due to an upgrade from 1200, SSDT displays the legacy UI for editing these metadata objects. By the same token, when you right-click a provider data source in Tabular Model Explorer and select Import New Tables, you launch the legacy UI for defining a query partition source. If you don't add any new data sources, the user interface is still consistent with the 1200 experience. Yet, if you mix provider and structured data sources in a model, the UI switches back and forth depending on what object type you edit. See the following screenshot with the modern experience on the left and the legacy UI on the right â€“ which one you see depends on the data source type you right-clicked.

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/PDS-vs-SDS-UI.png"><img width="879" height="424" class="alignnone size-large wp-image-3825" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/PDS-vs-SDS-UI-1024x494.png" /></a>
<h2>Fully enabling the legacy UI</h2>
BI professionals who prefer to build their Tabular models exclusively on top of SQL Server data warehouses using native T-SQL queries might look unfavorable at SSDT Tabular's strong bias towards the modern Get Data experience. But the good news is that you can fully enable the legacy UI to create provider data sources in Tabular 1400 models, so you don't need to resort to using TMSL or TOM for this purpose.

In the current version of SSDT Tabular, you must configure a DWORD parameter called "Enable Legacy Import" in the Windows registry. Setting this parameter to 1 enables the legacy UI. Setting it to zero or removing the parameter disables it again. To enable the legacy UI, you can copy the following lines into a .reg file and import the file into the registry. Do not forget to restart Visual Studio to apply the changes.
<pre>Windows Registry Editor Version 5.0

</pre>
<pre>[HKEY_CURRENT_USER\Software\Microsoft\Microsoft SQL Server\14.0\Microsoft Analysis Services\Settings]
"Enable Legacy Import"=dword:00000001</pre>
With the legacy UI fully enabled, you can right-click on Data Sources in Tabular Model Explorer and choose to Import From Data Source (Legacy) or reuse Existing Connections (Legacy), as in the following screenshot. As you would expect, these options create provider data sources in the model and then you can create query partitions on top of these.

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/Enabled-Legacy-UI.png"><img width="879" height="612" class="alignnone size-large wp-image-3815" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/Enabled-Legacy-UI-1024x713.png" /></a>
<h2>Wrapping things up</h2>
While AS engine, TMSL, and TOM give you full control over data sources and table partitions, SSDT Tabular attempts to simplify things by favoring M partitions over structured data sources wherever possible. The legacy UI only shows up if you already have provider data sources or query partitions in your model. Should legacy data sources and query partitions be first-class citizens in Tabular 1400? Perhaps SSDT should provide an explicit option in the user interface to enable the legacy UI to eliminate the need for configuring a registry parameter. Let us know if this is something we should do. Also, there is currently no SSDT support for creating M partitions over provider data sources or query partitions over structured data sources because these scenarios seem less important and less desirable. Do you need these features?

Send us your feedback via email to SSASPrev at Microsoft.com. Or use any other available communication channels such as UserVoice or MSDN forums. Or simply post a comment to this article. Influence the evolution of the Analysis Services connectivity stack to the benefit of all our customers!]]></content:encoded>
    </item>
    <item>
      <title>Using Azure Analysis Services on Top of Azure Data Lake Store</title>
      <link>https://docs.microsoft.com/archive/blogs/analysisservices/using-azure-analysis-services-on-top-of-azure-data-lake-storage</link>
      <pubDate>Tue, 05 Sep 2017 17:03:06 GMT</pubDate>
      <dc:creator><![CDATA[KayUnkroth]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/analysisservices/?p=3665</guid>
      <description><![CDATA[The latest release of SSDT Tabular adds support for Azure Data Lake Store (ADLS) to the modern Get...]]></description>
      <content:encoded><![CDATA[The <a href="https://marketplace.visualstudio.com/items?itemName=ProBITools.MicrosoftAnalysisServicesModelingProjects">latest release of SSDT Tabular</a> adds support for Azure Data Lake Store (ADLS) to the modern Get Data experience (see the following screenshot). Now you can augment your big data analytics workloads in Azure Data Lake with Azure Analysis Services and provide rich interactive analysis for selected data subsets at the speed of thought!

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/ADLS-Connector-Available.png"><img width="611" height="664" class="alignnone size-full wp-image-3675" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/ADLS-Connector-Available.png" /></a>

If you are unfamiliar with Azure Data Lake, check out the various articles at the <a href="https://azure.microsoft.com/en-us/solutions/data-lake/">Azure Data Lake product information</a> site. Also read the article <a href="https://docs.microsoft.com/en-us/azure/data-lake-analytics/data-lake-analytics-get-started-portal">"Get started with Azure Data Lake Analytics using Azure portal."</a>

Following these instructions, I provisioned a Data Lake Analytics account called <em>tpcds</em> for this article and a new Data Lake Store called <em>tpcdsadls</em>. I also added one of my existing Azure Blob Storage accounts, which contains a 1 TB TPC-DS data set, which I already created and used in the series <a href="https://blogs.msdn.microsoft.com/analysisservices/2017/05/15/building-an-azure-analysis-services-model-on-top-of-azure-blob-storage-part-1/">"Building an Azure Analysis Services Model on Top of Azure Blob Storage."</a> The idea is to move this data set into Azure Data Lake as a highly scalable and sophisticated analytics backend, from which to serve a variety of Azure Analysis Services models.

For starters, Azure Data Lake can process raw data and put it into targeted output files so that Azure Analysis Services can import the data with less overhead. For example, you can remove any unnecessary columns at the source, which eliminates about 60 GB of unnecessary data from my 1 TB TPC-DS data set and therefore benefits processing performance, as discussed in <a href="https://blogs.msdn.microsoft.com/analysisservices/2017/06/22/building-an-azure-analysis-services-model-on-top-of-azure-blob-storage-part-3/">"Building an Azure Analysis Services Model on Top of Azure Blob Storage--Part 3"</a>.

Moreover, with relatively little effort and a few small changes to a U-SQL script, you can provide multiple targeted data sets to your users, such as a small data set for modelling purposes plus one or more production data sets with the most relevant data. In this way, a data modeler can work efficiently in SSDT Tabular against the small data set prior to deployment, and after production deployment, business users can get the relevant information they need from your Azure Analysis Services models in Microsoft Power BI, Microsoft Office Excel, and Microsoft SQL Server Reporting Services. And if a data scientist still needs more than what's readily available in your models, you can use Azure Data Lake Analytics (ADLA) to run further U-SQL batch jobs directly against all the terabytes or petabytes of source data you may have. Of course, you can also take advantage of Azure HDInsight as a highly reliable, distributed and parallel programming framework for analyzing big data. The following diagram illustrates a possible combination of technologies on top of Azure Data Lake Store.

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/Analyze-Big-Data.png"><img width="879" height="470" class="alignnone size-large wp-image-3685" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/Analyze-Big-Data-1024x547.png" /></a>

Azure Data Lake Analytics (ADLA) can process massive volumes of data extremely quickly. Take a look at the following screenshot, which shows a Data Lake job processing approximately 2.8 billion rows of TPC-DS store sales data (~500 GB) in under 7 minutes!

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/Processing-Store-Sales.png"><img width="879" height="636" class="alignnone size-large wp-image-3735" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/Processing-Store-Sales-1024x741.png" /></a>

The screen in the background uses source files in Azure Data Lake Store and the screen in the foreground uses source files in Azure Blob Storage connected to Azure Data Lake. The performance is comparable, so I decided to leave my 1 TB TPC-DS data set in Azure Blob Storage, but if you want to ensure absolute best performance or would like to consolidate your data in one storage location, consider moving all your raw data files into ADLS. It's straightforward to copy data from Azure Blob Storage to ADLS by using the <a href="https://docs.microsoft.com/en-us/azure/data-lake-store/data-lake-store-copy-data-azure-storage-blob">AdlCopy</a> tool, for example.

With the raw source data in a Data Lake-accessible location, the next step is to define the U-SQL scripts to extract the relevant information and write it along with column names to a series of output files. The following listing shows a general U-SQL pattern that can be used for processing the raw TPC-DS data and putting it into comma-separated values (csv) files with a header row.
<pre>@raw_parsed = EXTRACT child_id int,
                <em>&lt;list of all table columns&gt;</em>,
                empty string
FROM "<em>&lt;URI to Blob Container&gt;</em>/{*}_{child_id}_100.dat"
USING Extractors.Text(delimiter: '|');

@filtered_results = SELECT <em>&lt;list of relevant table columns&gt;</em>
FROM @raw_parsed
<em>&lt;WHERE clause to extract specific rows for output&gt;</em>;

OUTPUT @filtered_results
TO "/<em>&lt;output folder&gt;</em>/<em>&lt;filename&gt;</em>.csv"
USING Outputters.Csv(outputHeader:true);</pre>
The next listing shows a concrete example based on the small <em>income_band</em> table. Note how the query extracts a portion of the file name into a virtual <em>child_id</em> column in addition to the actual columns from the source files. This <em>child_id</em> column comes in handy later when generating multiple output csv files for the large TPC-DS tables. Also, the WHERE clause is not strictly needed in this example because the <em>income_band</em> table only has 20 rows, but itâ€™s included to illustrate how to restrict the amount of data per table to a maximum of 100 rows to create a small modelling data set.
<pre>@raw_parsed = EXTRACT child_id int,
                      b_income_band_sk string,
                      b_lower_bound string,
                      b_upper_bound string,
                      empty string
FROM "wasb://income-band@aasuseast2/{*}_{child_id}_100.dat"
USING Extractors.Text(delimiter: '|');

@filtered_results = SELECT b_income_band_sk,
                           b_lower_bound,
                           b_upper_bound
FROM @raw_parsed
ORDER BY child_id ASC
FETCH 100 ROWS;</pre>
You can find complete sets of U-SQL scripts to generate output files for different scenarios (modelling, single csv file per table, multiple csv files for large tables, and large tables filtered by last available year) at the <a href="https://github.com/Microsoft/Analysis-Services/tree/master/UsqlScripts">GitHub repository for Analysis Services</a>.

For instance, for generating the modelling data set, there are 25 U-SQL scripts to generate a separate csv file for each TPC-DS table. You can run each U-SQL script manually in the Microsoft Azure portal, yet it is more convenient to use a small Microsoft PowerShell script for this purpose. Of course, you can also use Azure Data Factory, which among other things enables you to run U-SQL scripts on a scheduled basis. For this article, however, the following Microsoft PowerShell script suffices.
<pre>$script_folder = "&lt;<em>Path to U-SQL Scripts</em>&gt;"
$adla_account = "&lt;<em>ADLA Account Name</em>&gt;"
Login-AzureRmAccount -SubscriptionName "&lt;<em>Windows Azure Subscription Name</em>&gt;"

Get-ChildItem $script_folder -Filter *.usql |
Foreach-Object {
    $job = Submit-AdlJob -Name $_.Name -AccountName $adla_account â€“ScriptPath $_.FullName -DegreeOfParallelism 100
    Wait-AdlJob -Account $adla_account -JobId $job.JobId
}

Write-Host "Finished processing U-SQL jobs!";</pre>
It does not take long for Azure Data Lake to process the requests. You can use the Data Explorer feature in the Azure Portal to double-check that the desired csv files have been generated successfully, as the following screenshot illustrates.

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/Output-CSV-Files-for-Modelling.png"><img width="996" height="872" class="alignnone size-full wp-image-3725" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/Output-CSV-Files-for-Modelling.png" /></a>

With the modelling data set in place, you can finally switch over to SSDT and create a new Analysis Services Tabular model at the 1400 compatibility level. Make sure you have the latest version of the Microsoft Analysis Services Projects package installed so that you can pick Azure Data Lake Store from the list of available connectors. You will be prompted for the Azure Data Lake Store URL and you must sign in using an organizational account. Currently, the Azure Data Lake Store connector only supports interactive logons, which is an issue for processing the model in an automated way in Azure Analysis Services, as discussed later in this article. For now, let's focus on the modelling aspects.

The Azure Data Lake Store connector does not automatically establish an association between the folders or files in the store and the tables in the Tabular model. In other words, you must create each table individually and select the corresponding csv file in Query Editor. This is a minor inconvenience. It also implies that each table expression specifies the folder path to the desired csv file individually. If you are using a small data set from a modelling folder to create the Tabular model, you would need to modify every table expression during production deployment to point to the desired production data set in another folder. Fortunately, there is a way to centralize the folder navigation by using a shared expression so that only a single expression requires an update on production deployment. The following diagram depicts this design.

<a href="https://msdnshared.blob.core.windows.net/media//2017/09/Folder-Navigation-by-using-a-shared-Expression.png"><img width="656" height="595" class="alignnone size-large wp-image-3705" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/Folder-Navigation-by-using-a-shared-Expression.png" /></a>

To implement this design in a Tabular model, use the following steps:
<ol>
 	<li>Start Visual Studio and check under Tools -&gt; Extensions and Updates that you have the latest version of Microsoft Analysis Services Projects installed.</li>
 	<li>Create a new Tabular project at the 1400 compatibility level.</li>
 	<li>Open the Model menu and click on Import From Data Source.</li>
 	<li>Pick the Azure Data Lake Store connector, provide the storage account URL, and sign in by using an Organizational Account. Click Connect and then OK to create the data source object in the Tabular model.</li>
 	<li>Because you chose Import From Data Source, SSDT displays Query Editor automatically. In the Content column, click on the Table link next to the desired folder name (such as modelling) to navigate to the desired root folder where the csv files reside.</li>
 	<li>Right-click the Table object in the right Queries pane, and click Create Function. In the No Parameters Found dialog box, click Create.</li>
 	<li>In the Create Function dialog box, type GetCsvFileList, and then click OK.</li>
 	<li>Make sure the GetCsvFileList function is selected, and then on the View menu, click Advanced Editor.</li>
 	<li>In the Edit Function dialog box informing you that updates from the Table object will no longer propagate to the GetCsvFileList function if you continue, click OK.</li>
 	<li>In Advanced Editor, note how the GetCsvFileList function navigates to the modelling folder, enter a whitespace character at the end of the last line to modify the expression, and then click Done.</li>
 	<li>In the right Queries pane, select the Table object, and then in the left Applied Steps pane, delete the Navigation step, so that Source is the only remaining step.</li>
 	<li>Make sure the Formula Bar is displayed (View menu -&gt; Formula Bar), and then redefine the Source step as = GetCsvFileList() and press Enter. Verify that the list of csv files is displayed in Query Editor, as in the following screenshot.
<a href="https://msdnshared.blob.core.windows.net/media/2017/09/Invoke-GetCsvFileList.png"><img width="879" height="571" class="alignnone size-large wp-image-3715" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/Invoke-GetCsvFileList-1024x665.png" /></a></li>
 	<li>For each table you want to import:
<ol>
 	<li>Right-click the existing Table object and click Duplicate.</li>
 	<li>In the Content column, click on the Binary link next to the desired file name (such as call_center) and verify that Query Editor parses the columns and detects the data types correctly.</li>
 	<li>Rename the table according to the csv file you selected (such as call_center).</li>
 	<li>Right-click the renamed table object (such as call_center) in the Queries pane and click Create New Table.</li>
 	<li>Verify that the renamed table object (such as call_center) is no longer displayed in italic, which indicates that the query will now be imported as a table into the Tabular model.</li>
</ol>
</li>
 	<li>After you created all desired tables by using the sequence above, delete the original Table object by right-clicking on it and selecting Delete.</li>
 	<li>In Query Editor, click Import to add the GetCsvFileList expression and the tables to your Tabular model.</li>
</ol>
During the import, SSDT Tabular pulls in the small modelling data set. And prior to production deployment, it is now a simple matter of updating the shared expression by right-clicking on the Expressions node in Tabular Model Explorer and selecting Edit Expressions, and then changing the folder name in Advanced Editor. The below screenshot highlights the folder name in the GetCsvFileList expression. And if each table can find its corresponding csv file in the new folder location, deployment and processing can succeed.

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/Changing-the-CSV-Folder.png"><img width="879" height="553" class="alignnone size-large wp-image-3695" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/Changing-the-CSV-Folder-1024x644.png" /></a>

Another option is to deploy the model with the Do Not Process deployment option and use a small TOM application in Azure Functions to process the model on a scheduled basis. Of course, you can also use SSMS to connect to your Azure Analysis Services server and send a processing command, but it might be inconvenient to keep SSDT or SSMS connected for the duration of the processing cycle. Processing against the full 1 TB data set with a single csv file per table took about 15 hours to complete. Processing with four csv files/partitions for the seven large tables and maxActiveConnections on the data source set to 46 concurrent connections took roughly 6 hours. This is remarkably faster in comparison to using general BLOB storage, as in the <a href="https://blogs.msdn.microsoft.com/analysisservices/2017/06/22/building-an-azure-analysis-services-model-on-top-of-azure-blob-storage-part-3/">Building an Azure Analysis Services Model on Top of Azure Blob Storage article</a>, and suggests that there is potential for performance improvements in the Azure BLOB storage connector.

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/Processing.png"><img width="879" height="454" class="alignnone size-large wp-image-3745" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/Processing-1024x529.png" /></a>

Even the processing performance against Azure Data Lake could possibly be further increased, as the processor utilization on an S9 Azure Analysis Server suggests (see the following screenshot). For the first 30 minutes, processor utilization is close to the maximum and then it decreases as the AS engine finishes more and more partitions and tables. Perhaps with an even higher degree of parallelism, such as with eight or twelve partitions for each large table, Azure AS could keep processor utilization near the maximum for longer and finish the processing work sooner. But processing optimizations through elaborate table partitioning schemes is beyond the scope of this article. The processing performance achieved with four partitions on each large table suffices to conclude that Azure Data Lake is a very suitable big-data backend for Azure Analysis Services.

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/QPUs.png"><img width="879" height="302" class="alignnone size-large wp-image-3755" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/QPUs-1024x352.png" /></a>

There is currently only one important caveat: The Azure Data Lake Store connector only supports interactive logons. When you define the Azure Data Lake Store data source, SSDT prompts you to log on to Azure Data Lake. The connector performs the logon and then stores the obtained authentication token in the model. However, this token only has a limited lifetime. Chances are fair that processing succeeds after the initial deployment, but when you come back the next day and want to process again, you get an error that "<em>The credentials provided for the DataLake source are invalid.</em>" See the screenshot below. Either you deploy the model again in SSDT or you right-click the data source in SSMS and select Refresh Credentials to log on to Data Lake again and submit fresh tokens to the model. Note that you must use at least version 15.6 of SSMS to refresh the credentials.

<a href="https://msdnshared.blob.core.windows.net/media/2017/09/refresh_creds.png"><img width="879" height="609" class="alignnone size-large wp-image-3756" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/09/refresh_creds-1024x710.png" /></a>

A subsequent article is going to cover how to handle authentication tokens programmatically, so stay tuned for more on connecting to Azure Data Lake and other big data sources on the Analysis Services team blog. And as always, please deploy the latest monthly release of SSDT Tabular and send us your feedback and suggestions by using SSASPrev at Microsoft.com or any other available communication channels such as UserVoice or MSDN forums.]]></content:encoded>
    </item>
    <item>
      <title>Supporting Advanced Data Access Scenarios in Tabular 1400 Models</title>
      <link>https://docs.microsoft.com/archive/blogs/analysisservices/supporting-advanced-data-access-scenarios-in-tabular-1400-models</link>
      <pubDate>Mon, 28 Aug 2017 16:19:12 GMT</pubDate>
      <dc:creator><![CDATA[KayUnkroth]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/analysisservices/?p=3635</guid>
      <description><![CDATA[In the context of this blog article, advanced data access scenarios refers to situations where data...]]></description>
      <content:encoded><![CDATA[In the context of this blog article, <em>advanced data access scenarios</em> refers to situations where data access functions inside M expressions cannot easily be represented through data source definitions in Tabular metadata. These scenarios are predominantly encountered when copying and pasting complex M expressions from an Excel workbook or a Power BI Desktop file into a Tabular 1400 model, or when <a href="https://azure.microsoft.com/en-us/blog/import-power-bi-desktop-files-into-azure-analysis-services/">importing Power BI Desktop files into Azure Analysis Services</a>. Often, these complex M expressions require manual tweaking for processing of the Tabular 1400 model to succeed.
<h1>Background information</h1>
Before jumping into these advanced data access scenarios, let's review two basic concepts that differ between M expressions in Power BI Desktop files and in Tabular 1400 models: Data Source Representations (DSRs) and Credentials/Privacy Settings. Understanding the differences is a prerequisite to mastering the advanced data access scenarios covered later in this article.

In Power BI Desktop, you can write a very simplistic M expression like the following and import the resulting table of database objects into your data model:
<pre>let
    Source = Sql.Database("server01", "AdventureWorksDW")
in
    Source</pre>
Yet, in Tabular 1400, you first need to define a data source in the model, perhaps called "<em>SQL/server01;AdventureWorksDW"</em>, and then write the M expression like this:
<pre>let
    Source = #"SQL/server01;AdventureWorksDW"
in
    Source</pre>
The result is the same. So why did Tabular 1400 models introduce a different way of providing the data source information? One of the main reasons is explicit data source definitions facilitate deployments. Instead of editing 50 table expressions in a model as part of a production deployment, you can simply edit a single data source definition and all 50 table expressions access the correct production data source. Another key requirement is programmability. While SSDT Tabular is certainly a main tool for creating Tabular 1400 models, it's by no means the only one. In fact, many Tabular models are created and deployed in an automated way through scripts or ETL packages. The ability to define data sources in a model programmatically is very important.

Going one level deeper, check out the <a href="https://msdn.microsoft.com/en-us/library/mt260902.aspx">definition of the Sql.Database function in the Power Query (M) Formula Reference</a>. You can see it is defined as in the Data Access Function column of the following table. Next, look at a structured data source definition for SQL Server in a Model.bim file of a Tabular 1400 model. The data source definition follows the format shown in the Data Source Definition column of the below table. A side-by-side comparison shows you that all parameters of the Sql.Database function are also available in the data source definition. That's not surprising. However, the Mashup engine only works with M expressions. It doesn't know anything about Tabular 1400 metadata. During modeling and processing, the tools and the AS engine must translate the data access functions and their data source definitions back and forth with the help of the Mashup engine.
<table>
<tbody>
<tr>
<td width="312"><strong>Data Access Function</strong></td>
<td width="312"><strong>Data Source Definition</strong></td>
</tr>
<tr>
<td width="312">Sql.Database(
server as text<span>, </span>database as text,
optional options as nullable record) as table</td>
<td width="312">{
"type": "structured",
"name": "name as text",
"connectionDetails": {
"protocol": "tds",
"address": {
"server": "server as text",
"database": "database as text"
},
"authentication": null,
"query": "optional query as text"
},
"options": {optional options as nullable record}
"credential": {...}
}</td>
</tr>
</tbody>
</table>
&nbsp;

As a side note, if your M expressions in Power BI Desktop use data access functions that do not yet have a data source representation in Tabular 1400, then you cannot use these M expressions in your Tabular 1400 model. We first must enable/extend the corresponding connector. Our goal is to add a data source representation to every connector available in Power BI Desktop and then enable these connectors for Tabular 1400.

So far, things are relatively straightforward. But, it gets tricky when credential objects come into the picture. In the M expressions above, where are the credentials to access the data source? Power BI Desktop stores the credentials in a user-specific location on the local computer. This mechanism doesn't work for Tabular 1400 because these models are hosted on an Analysis Services server. The credentials are stored in the credential property of the structured data source in the model metadata (see the data source definition in the table above).

Given that Power BI Desktop stores the credentials outside of the .pbix file, how does the Mashup engine know which credentials to use for which data source? The crucial detail is the Mashup engine uses the data access parameters to establish the association between the data access functions and their credentials. In other words, if your Power BI Desktop file includes multiple Sql.Database("server01", "AdventureWorksDW") statements, because they all use the same address parameters, there is only one credential for all of them. You can notice this in Power BI Desktop as you are prompted only once for credentials to access a given data source, no matter how often you use the corresponding data access function. By default, Power BI Desktop associates a credential with the highest level of the address parameters, such as the SQL Server server name. But you can select lower levels if the data source supports it, such as server and database name, as shown in the following screenshot.

<a href="https://msdnshared.blob.core.windows.net/media/2017/08/MExpCredentialLevel.png"><img width="695" height="406" class="alignnone size-full wp-image-3655" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/08/MExpCredentialLevel.png" /></a>

The tricky part is the same association rules apply to Tabular 1400. Theoretically, each data source definition in a Tabular 1400 model has its own credential object. This is certainly the case at the Tabular metadata layer. But as mentioned earlier, the Mashup engine does not deal with Tabular metadata. The Mashup engine expects M expressions with resolved data access functions. The AS engine must translate the structured data source definitions accordingly. If two data source definitions had the same address parameters, it would no longer be possible to identify their corresponding credential objects uniquely at the M layer. To avoid credential ambiguity, there can be only one data source definition with a given set of address parameters in a Tabular 1400 model. Plans exist to eliminate this restriction in a future compatibility level, but in Tabular 1400 this limitation is important to keep in mind when dealing with advanced data access scenarios.

Now, let's jump into these advanced data access scenarios with increasing levels of complexity.
<h1>Accessing the same data source with different options</h1>
As a warmup, look at the following M expression. It's not very useful, but it illustrates the point. The expression includes two Sql.Database calls with the same address parameters, but with different options. As explained above, in Tabular 1400, you cannot create two separate data source objects for these two function calls. But if you can only create one, then you only get one options record (see the previous table). So what are you going to do with the second command timeout? Can you perhaps use the same command timeout and consolidate both into a single data source definition? What if not?
<pre>let
    Source1 = Sql.Database("server01", "AdventureWorksDW", [CommandTimeout=#duration(0, 0, 5, 0)]),
    Source2 = Sql.Database("server01", "AdventureWorksDW", [CommandTimeout=#duration(0, 0, 10, 0)]),
    Combined = Table.Combine({Source1, Source2})
in
    Combined</pre>
The solution is not intuitive. Perhaps even misleading. It is fragile, and it breaks dependency analysis in the tools. It also breaks the programmability contract because you can no longer simply update the data source definition and expect your M expressions to pick up the changes. It clearly needs a better implementation in a future compatibility level. But for now, you can simply define a data source with the address parameters shown above and then use the M expression unmodified in Tabular 1400. The credential object is magically applied to all corresponding data access functions that use the same parameters across all M expressions in the model. That's how the Mashup engine works, as the following screenshot illustrates.

<a href="https://msdnshared.blob.core.windows.net/media/2017/08/MExpDataAccessDifferentOptions.png"><img width="879" height="553" class="alignnone size-large wp-image-3636" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/08/MExpDataAccessDifferentOptions-1024x644.png" /></a>
<blockquote><strong>Note:</strong> This workaround of using a data source merely as a holder of a credential object is not recommended and should be considered a last-resort option. If possible, create a common set of options for all data access calls to the same source and use a single data source object to replace the data access functions. Another option might be to register the same server with multiple names in DNS and then use a different server name in each data source definition.</blockquote>
<h1>Accessing the same data source with different native queries</h1>
Perhaps, you can consolidate your data access options and keep things straightforward in your Tabular 1400 model. But what if your data access functions use different native queries as in the following example?
<pre>let
    Source1 = Sql.Database("server01", "AdventureWorksDW", [Query="SELECT * FROM dimCustomer WHERE LastName = 'Walker'"]),
    Source2 = Sql.Database("server01", "AdventureWorksDW", [Query="SELECT * FROM dimCustomer WHERE LastName = 'Jenkins'"]),
    Combined = Table.Combine({Source1, Source2})
in
    Combined</pre>
Of course, one option is to rewrite the first native query to deliver the combined result so that you can eliminate the second function call. Yet, native query rewrites are not really required if you modified the M expression and used the Value.NativeQuery function, as in the following expression. Now there is only a single Sql.Database function call, which can nicely be replaced with a data source definition in Tabular 1400.
<pre>let
    Source = Sql.Database("server01", "AdventureWorksDW"),
    Table1 = Value.NativeQuery(Source, "SELECT * FROM dimCustomer WHERE LastName = 'Walker'"),
    Table2 = Value.NativeQuery(Source, "SELECT * FROM dimCustomer WHERE LastName = 'Jenkins'"),
    Combined = Table.Combine({Table1, Table2})
in
    Combined</pre>
<blockquote><strong>Note:</strong> Even if you consolidated the queries, as in <em>SELECT * FROM dimCustomer WHERE LastName = 'Walker' Or LastName = 'Jenkins'</em>, avoid putting this native query on the <em>query</em> parameter of the data source definition. The <em>query</em> parameter exists for full compatibility between data access functions and data source definitions. But it shouldn't be used because it narrows the data source down to a particular query. You could not import any other data from that source. As explained earlier, you cannot define a second data source object with the same address parameters in Tabular 1400. So, define the data source in broadest terms and then use the Value.NativeQuery function to submit a native query.</blockquote>
<h1>Handling parameterized data access functions</h1>
The next level of challenges revolves around the dynamic definition data source parameters. This technique is occasionally used in Power BI Desktop files to maintain the address parameters for multiple data access function calls centrally. The following screenshot shows an example.

<a href="https://msdnshared.blob.core.windows.net/media/2017/08/MExpParameterized-Data-Access-Function.png"><img width="879" height="624" class="alignnone size-large wp-image-3637" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/08/MExpParameterized-Data-Access-Function-1024x727.png" /></a>

Fortunately, the concept of M-based address parameter definitions is comparable to the concept of a data source definition in Tabular 1400. In most cases, you should be able to define the Tabular 1400 data source as always by simply using the parameter values directly. Then, replace the data access function calls in your M expressions with the reference to the data source, delete the M-based parameter definitions, and the job is done. The result is a common Tabular 1400 M expression.
<pre>let
    Source = #"SQL/server01;AdventureWorksDW"
in
    Source</pre>
Of course, this technique only works for trivial, single-valued parameter definitions. For more complex scenarios, well, read on.
<h1>Dealing with Dynamic Data Access Functions</h1>
The ultimate challenge in the <em>advanced data access scenarios</em> is the fully dynamic implementation of a data access function call. There are various flavors. Let's analyze the following simple example first.
<pre>let
    #"Dynamic Function" = Sql.Database,
    Source = #"Dynamic Function"("server01", "AdventureWorksDW")
in
    Source</pre>
Clearly, this M expression is accessing a SQL Server database called AdventureWorksDW on server01. You can create a data source definition for this database in Tabular 1400 and replace these lines with a reference to that data source definition, as shown in the sample in the previous section above. This is easy because it wasn't really a dynamic data source, yet. Here's a fully dynamic example.
<pre>let
    Source = Sql.Database("server01", "Dynamic"),
    DataAccessPoints = Source{[Schema="dbo",Item="DataAccessPoints"]}[Data],
    NavigationTable = Table.AddColumn(DataAccessPoints, "Data", each Connect([FunctionName], [Parameter1], [Parameter2]))
in
    NavigationTable</pre>
This M expression retrieves all rows from a DataAccessPoints table in a SQL Server database called Dynamic. It then passes the column values of each row to a custom function called Connect, which then connects to the specified data source. The Connect function is based on the following M expression.
<pre>let
    Source = (FunctionName, Param1, Param2) =&gt; let
        FunctionTable = Record.ToTable(#shared),
        FunctionRow = Table.SelectRows(FunctionTable, each ([Name] = FunctionName)),
        Function = FunctionRow{0}[Value],
        Result = if Param2 = null then Function(Param1) else Function(Param1, Param2)
    in
        Result
in
    Source</pre>
Not only are the address parameters (Param1 and Param2) dynamically assigned, but the name of the data access function itself is also passed in as a parameter (FunctionName). So, unless you know the contents of the DataAccessPoints table, you cannot even determine what data sources this M expression accesses! You must evaluate the expressions against the actual data to know what credentials you need to supply, and you must define privacy settings. In this example, the following screenshot reveals that the expressions connect to an OData feed as well as a SQL Server database, but it could really be any supported data source type.
<a href="https://msdnshared.blob.core.windows.net/media/2017/08/MExp-Fully-Dynamic-Data-Access.png"><img width="879" height="616" class="alignnone size-large wp-image-3645" alt="" src="https://msdnshared.blob.core.windows.net/media/2017/08/MExp-Fully-Dynamic-Data-Access-1024x718.png" /></a>
So, if you wanted to use such a dynamic construct, you would have to create the corresponding data source objects with their credentials in your Tabular 1400 model. Power BI Desktop can prompt you for the missing credentials if you added a new entry to the DataAccessPoints table, but Analysis Services cannot because there is no interactive user on a server, and processing would fail. You must add a new matching data source definition with the missing credentials and privacy settings upfront, which somewhat defeats the purpose of a fully dynamic data source definition.
<h1>Looking to the future</h1>
Perhaps you are wondering at this point why we didn't provide more flexible support for credential handling in Tabular 1400. One of the main reasons is the footprint of the modern Get Data experience on the Mashup engine is already significant. It wasn't justifiable to take a sledgehammer approach at the Mashup layer. Especially when it concerns security features used across several Microsoft technologies, including Power BI.

Fully dynamic scenarios are certainly interesting and fun, but they are corner cases. The more common advanced data access scenarios can be handled with moderate effort in Tabular 1400. And a future compatibility level is going to remove the limitation of a single data source definition per target parameters. It requires some replumbing deep in the Mashup engine. On the other hand, how Tabular models are going to support fully dynamic data source definitions in future compatibility levels hasn't yet been decided. One idea is to move credential storage out of the Tabular metadata. Another is to introduce new metadata objects that can be associated with data access functions through their address parameters. Perhaps another is to invent a form of processing handshake. And there may be other options. If you have a great idea, please post a comment or send it our way via ssasprev at microsoft.com, or use any other available communication channels such as UserVoice or MSDN forums.

That's it for this excursion into handling advanced data access scenarios when moving M expressions from Power BI Desktop to a Tabular 1400 model. One of the next articles will show you how to use legacy provider data sources and native query partitions together with the new structured data sources and M partitions in a Tabular 1400 model. Stay tuned for more Get Data coverage on the Analysis Services Team Blog!]]></content:encoded>
    </item>
  </channel>
</rss>