<?xml version="1.0" encoding="utf-8" ?>

<rss version="2.0" 
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:admin="http://webns.net/mvcb/"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
   xmlns:wfw="http://wellformedweb.org/CommentAPI/"
   xmlns:content="http://purl.org/rss/1.0/modules/content/"
   >
<channel>
    
    <title>Addicted2AX / Addicted2SQL - Performance</title>
    <link>http://addicted2ax.de/</link>
    <description>My daily struggle with Dynamics AX &amp; SQL Server</description>
    <dc:language>en</dc:language>
    <generator>Serendipity 1.5.5 - http://www.s9y.org/</generator>
    <pubDate>Thu, 22 Mar 2012 18:15:09 GMT</pubDate>

    <image>
        <url>http://addicted2ax.de/templates/default/img/s9y_banner_small.png</url>
        <title>RSS: Addicted2AX / Addicted2SQL - Performance - My daily struggle with Dynamics AX &amp; SQL Server</title>
        <link>http://addicted2ax.de/</link>
        <width>100</width>
        <height>21</height>
    </image>

<item>
    <title>Dynamics AX 2012 &amp; SQL Server 2008R2: Cross Join vs. Inner Join – Houston we have *NO* Problem</title>
    <link>http://addicted2ax.de/index.php?/archives/22-Dynamics-AX-2012-SQL-Server-2008R2-Cross-Join-vs.-Inner-Join-Houston-we-have-NO-Problem.html</link>
            <category>Performance</category>
            <category>Performance</category>
    
    <comments>http://addicted2ax.de/index.php?/archives/22-Dynamics-AX-2012-SQL-Server-2008R2-Cross-Join-vs.-Inner-Join-Houston-we-have-NO-Problem.html#comments</comments>
    <wfw:comment>http://addicted2ax.de/wfwcomment.php?cid=22</wfw:comment>

    <slash:comments>0</slash:comments>
    <wfw:commentRss>http://addicted2ax.de/rss.php?version=2.0&amp;type=comments&amp;cid=22</wfw:commentRss>
    

    <author>nospam@example.com (Addicted2AX)</author>
    <content:encoded>
    Recently I had to bulid a rather complex list page. The Dynamics AX 2012-query contained some INNER JOINS and some OUTER JOINS between tables. After finishing designing the list page the performance when running the list page was suboptimal.&lt;br /&gt;
 &lt;br /&gt;
After adding some indexes performance increased drastic but still had some room for improvement.&lt;br /&gt;
&lt;br /&gt;
So I ran an SQL Server Profiler Trace and was a little bit shocked for a moment: The SQL statement which was created Dynamics AX 2012  to be send to SQL Server 2008 R2 was a CROSS JOIN with a WHERE-clause and not an INNER JOIN.&lt;br /&gt;
&lt;br /&gt;
First thought was that I remembered that a CROSS JOIN creates a cartesian product of both tables. Cartesian product means that every of the first table is joined with every row of the second table. Then I remebered that a CROSS JOIN with a WHERE-clause delivers in the end the same result as an INNER JOIN.&lt;br /&gt;
Second though was that in other RDBMS and older versions of SQL Server even when the result is the same like in an INNER JOIN a CROSS JOIN with a WHERE-Clause may perform not as good as an INNER JOIN.&lt;br /&gt;
&lt;br /&gt;
So my idea was to check if there is maybe a performance problem in Dynamics AX 2012 by using CROSS JOINS instead of using INNER JOINS.&lt;br /&gt;
Firstly I bulid a query using SalesTable-table joined with SalesLine-table using an INNER JOIN as join mode and as fetch mode “1:n”. I have also tested “1:1”. Ressults were identically.&lt;br /&gt;
&lt;br /&gt;
&lt;img class=&quot;serendipity_image_center&quot; width=&quot;723&quot; height=&quot;398&quot;  src=&quot;http://addicted2ax.de/uploads/2012-03-13/QueryAX.gif&quot;  alt=&quot;&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
For test purposes I used „forced Literals“ and the following SQL Statement was send to SQL Server by Dynamics AX 2012&lt;br /&gt;
&lt;br /&gt;
&lt;img class=&quot;serendipity_image_center&quot; width=&quot;793&quot; height=&quot;369&quot;  src=&quot;http://addicted2ax.de/uploads/2012-03-13/CrossJoin.gif&quot;  alt=&quot;&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
Execution Plan looks quite good: For both tables a „Clustered Index Seek“ was performed. Then both result sets were joined. Finished. Looks quite good to me.&lt;br /&gt;
&lt;br /&gt;
Let’s see what statistics say:&lt;br /&gt;
&lt;br /&gt;
&lt;img class=&quot;serendipity_image_center&quot; width=&quot;620&quot; height=&quot;457&quot;  src=&quot;http://addicted2ax.de/uploads/2012-03-13/CrossJoinStatistics.gif&quot;  alt=&quot;&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
434 logical reads for SalesLine-table and 163 logical reads for SalesTable. CPU-time used: 47ms. Total elapsed time: round about 2 seconds. &lt;br /&gt;
Not bad, but maybe an INNER JOIN performs even better.&lt;br /&gt;
&lt;br /&gt;
The following SQL statement using an INNER JOIN was built by me in the way how I would have built it if I was Dynamics AX 2012.&lt;br /&gt;
&lt;br /&gt;
&lt;img class=&quot;serendipity_image_center&quot; width=&quot;662&quot; height=&quot;400&quot;  src=&quot;http://addicted2ax.de/uploads/2012-03-13/InnerJoin.gif&quot;  alt=&quot;&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
I must confess that I was a little bit surprised that both Execution Plans were identically.&lt;br /&gt;
&lt;br /&gt;
Checking statistics shows the same result: Same numbers of reads for SalesTable-table and SalesLine-table. Differences in CPU-time and in total elapsed time are inside normal fluctuations when running SQL Server. So needed time when running a CROSS JOIN with a WHERE-clause and time needed when running an INNER JOIN can said to be identically.&lt;br /&gt;
&lt;br /&gt;
&lt;img class=&quot;serendipity_image_center&quot; width=&quot;656&quot; height=&quot;474&quot;  src=&quot;http://addicted2ax.de/uploads/2012-03-13/InnerJoinStatistics.gif&quot;  alt=&quot;&quot; /&gt;&lt;br /&gt;
&lt;br /&gt;
A short Google-search showed the following result. Last version of SQL Server which seemed to perform a CROSS JOIN with a WHERE-clause worse than an INNER JOIN was SQL Server 2000. Since SQL Server 2005 query optimizer treats a CROSS JOIN with a WHERE-clause identically to an INNER JOIN. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;&lt;strong&gt;Update 22.03.2012:&lt;/strong&gt;&lt;/u&gt;&lt;br /&gt;
I faced a (minor) problem with a CROSS JOIN with WHERE-clause: I joined two tables in a larger query by using Expression “Relation” with value “Yes” (by setting Expression “Relation” to “Yes” relations are set automatically using the relations specified in Relations-knot of the specific table).&lt;br /&gt;
&lt;br /&gt;
Even so the relation seemed to be set correctly in Dynamics AX 2012 the SQL Statement generated by Dynamics AX 2012 was not generated correctly: Only a CROSS JOIN without a WHERE-clause was generated. So the CROSS JOIN generated a cartesian product with a large amount of data. &lt;br /&gt;
Fastest and proper working solution I found was setting back “Relation” to “No” and rebuilding the relation manually. Manually generated relation has exactly the same values as the automatically generation.&lt;br /&gt;
&lt;br /&gt;
This seems &lt;strong&gt;NOT&lt;/strong&gt; to be a general problem, because the other automatically generated relations between the tables of the query work proper and without any problem. I also had no problem using Expression “Relation” with value “Yes” with other queries.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;&lt;/u&gt; &lt;br /&gt;
When Dynamics AX 2012 generates a CROSS JOIN with a WHERE-clause instead of an INNER JOIN when performing an INNER JOIN: There is no performance gap.&lt;br /&gt;
If you have any with unexpected result sets which may look like a cartesian product check the relations between the tables, kill the existing automatically build relations and rebuild these relations manually. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 
    </content:encoded>

    <pubDate>Tue, 13 Mar 2012 21:48:19 +0100</pubDate>
    <guid isPermaLink="false">http://addicted2ax.de/index.php?/archives/22-guid.html</guid>
    <category>cross join</category>
<category>dynamics ax 2012</category>
<category>indexes</category>
<category>inner join</category>
<category>performance</category>
<category>sql server 2000</category>
<category>sql server 2005</category>
<category>sql server 2008r2</category>
<category>where-clause</category>

</item>

</channel>
</rss>