
{"id":265,"date":"2017-05-19T11:20:11","date_gmt":"2017-05-19T01:20:11","guid":{"rendered":"http:\/\/bakke.online\/?p=265"},"modified":"2022-01-22T20:10:56","modified_gmt":"2022-01-22T09:10:56","slug":"too-many-joins-in-query","status":"publish","type":"post","link":"https:\/\/www.bakke.online\/index.php\/2017\/05\/19\/too-many-joins-in-query\/","title":{"rendered":"Too many joins in query"},"content":{"rendered":"<p>In Dynamics AX 2012, if you are running a query with too many joins you can get an error or warning message saying &#8220;The number of joins in the statement is XX. \u00a0This exceeds the maximum of 26. \u00a0Turn on exception for this warning to see the call stack.&#8221;<\/p>\n<p><a href=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/toomanyjoins.png\"><br \/>\n<\/a><a href=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/toomanyjoins.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-266\" src=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/toomanyjoins.png\" alt=\"\" width=\"845\" height=\"336\" \/><\/a><\/p>\n<p>So what is this, and what can you do about it?<\/p>\n<p><!--more--><\/p>\n<p>Running queries with too many joins is not a particularly good idea from a performance point of view, so your first preference should be to rework the query into something simpler, something which doesn&#8217;t make SQL Server fall on its knees begging for mercy, so let&#8217;s take a look at that first.<\/p>\n<p><strong>The following steps will require restarting the AOS, so make sure you can reproduce the problem in a non-production environment first.<\/strong><\/p>\n<h3>Simplifying the query<\/h3>\n<p>If you don&#8217;t already know where the query is being called from, follow the suggestion in the warning message and turn on exceptions for this warning. \u00a0Unfortunately the message doesn&#8217;t actually say where and how to do this&#8230;<\/p>\n<p><a href=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/serverconfig_menu.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-267\" src=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/serverconfig_menu.png\" alt=\"\" width=\"215\" height=\"441\" \/><\/a><\/p>\n<p>To make the change, go to the System Administration menu, Setup, System and then Server Configuration. \u00a0In the Performance Optimisation tab, find the &#8220;Error on exceeding maximum number of tables in join&#8221; setting and change it to Yes.<\/p>\n<p><a href=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/serverconfig_error.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-268 size-full\" src=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/serverconfig_error.png\" width=\"780\" height=\"475\" \/><\/a><\/p>\n<p>Close AX and restart the AOS. \u00a0(Non-production, right?)<\/p>\n<p>Now, try that query again:<\/p>\n<p><a href=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/toomanyjoins_stacktrace.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-270\" src=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/toomanyjoins_stacktrace.png\" alt=\"\" width=\"566\" height=\"353\" \/><\/a><\/p>\n<p>Ah, that&#8217;s where it is hiding&#8230; \u00a0(Don&#8217;t mind the fact that the error message shows %2 instead of the number of joins, it&#8217;s above the limit, and that&#8217;s what&#8217;s important)<\/p>\n<p>So, how to simplify the query? \u00a0It can be split\u00a0into smaller queries which each retrieve only parts of the data, either in an X++ loop over an outer query and a call to get the inner query for each iteration, or by setting the FetchMode property to &#8220;1:n&#8221; on one or more branches of the query.<\/p>\n<p><a href=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/fetchmode.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-271\" src=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/fetchmode.png\" alt=\"\" width=\"273\" height=\"103\" \/><\/a><\/p>\n<p>Here I&#8217;m assuming that you are doing this through an AOT query. \u00a0If you are building this query in X++ or with a while-select statement&#8230; What are you doing??? \u00a0That sort of stuff gets REALLY painful with queries this complex.<\/p>\n<p>Another way of simplifying the query would be to split one or more query branches off into views, backed by their own queries. \u00a0This will still let you run the query with 1:1 FetchMode without this error, but unfortunately it will not make SQL Server&#8217;s job any easier. \u00a0Actually, unless you manage to get the predicates pushed down to the nested views, performance will go down, not up&#8230;<\/p>\n<p>I know it is the AX way, to build queries, based on views, based on other queries again based on views, based on further queries. \u00a0(Bank transaction views and global address book views, anyone?) \u00a0However, this smells more of a workaround than a solution, and when you start looking into the SQL Server query plans those things generate you&#8217;ll see why.<\/p>\n<h3>What if I can&#8217;t change the query?<\/h3>\n<p>If you can&#8217;t change the query, your only other option is to increase the maximum limit for number of joins in a query.<\/p>\n<p>To do that, open the Server Configuration form as described above and change the &#8220;Maximum number of tables in join&#8221;, close the form and restart the AOS.<\/p>\n<p><a href=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/maxtablesperjoin.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-272\" src=\"https:\/\/www.bakke.online\/wp-content\/uploads\/2017\/05\/maxtablesperjoin.png\" alt=\"\" width=\"766\" height=\"454\" \/><\/a><\/p>\n<p>Please consider this to be a workaround as well and be aware of the performance implications raising this limit can have. \u00a0This limit only controls the number of tables (or views) that can be joined in a single call from AX to the database, and it is possible to get into the same (or worse) performance problems by splitting up the query, converting to use views for query branches, etc.<\/p>\n<p>When your query is working, time it, measure the performance of it. \u00a0Use the Dynamics AX Trace Parser to capture the SQL statement your query generates and sends to SQL Server and run that query through a tool like <a href=\"https:\/\/www.sentryone.com\/plan-explorer\/\">SQL Sentry Plan Explorer<\/a> or similar.<\/p>\n<h3>The real solution<\/h3>\n<p>Unfortunately, the real solution is usually the one which requires the most work. \u00a0Review the requirements and the solution architecture to find out\u00a0<strong>why<\/strong> such massive joins are required, and even\u00a0<strong>if<\/strong> they are required at all. \u00a0It is extremely likely that the code and data can be restructured to avoid it, and that will be the best way to get good performance out of your queries.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In Dynamics AX 2012, if you are running a query with too many joins you can get an error or warning message saying &#8220;The number of joins in the statement is XX. \u00a0This exceeds the maximum of 26. \u00a0Turn on exception for this warning to see the call stack.&#8221; So what is this, and what &hellip; <a href=\"https:\/\/www.bakke.online\/index.php\/2017\/05\/19\/too-many-joins-in-query\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Too many joins in query&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,1],"tags":[2,3,6,22],"class_list":["post-265","post","type-post","status-publish","format-standard","hentry","category-dynamics-ax","category-uncategorized","tag-ax2012r3","tag-dynamics-ax","tag-error-messages","tag-performance"],"_links":{"self":[{"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/posts\/265","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/comments?post=265"}],"version-history":[{"count":1,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/posts\/265\/revisions"}],"predecessor-version":[{"id":1341,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/posts\/265\/revisions\/1341"}],"wp:attachment":[{"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/media?parent=265"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/categories?post=265"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bakke.online\/index.php\/wp-json\/wp\/v2\/tags?post=265"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}