{"id":1443,"date":"2012-12-20T10:00:43","date_gmt":"2012-12-20T15:00:43","guid":{"rendered":"http:\/\/sqlity.net\/en\/?p=1443"},"modified":"2014-11-13T13:50:40","modified_gmt":"2014-11-13T18:50:40","slug":"a-join-a-day-join-hints","status":"publish","type":"post","link":"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/","title":{"rendered":"A Join A Day \u2013 Join Hints"},"content":{"rendered":"<div>\n<h3>Introduction<\/h3>\n<p>\nThis is the twentieth post in my <a href=\"http:\/\/sqlity.net\/en\/1146\/a-join-a-day-introduction\/\">A Join A Day<\/a> series about SQL Server Joins. Make sure to let me know how I am doing or ask your burning join related questions by leaving a comment below.\n<\/p>\n<p>\nBefore SQL Server can execute a query it needs to compile it into an execution plan. The compilation is done by the optimizer. The optimizer is looking at possible execution plans for the query and is trying to identify the best one. Yesterday we learned that the order of tables in a join does not change the result. Reordering the tables in a join construct can already lead to very many plans. There are six possible orders when three tables are involved, 24 with four tables and 120 with five tables. There are also many other options that the optimizer has to choose from, for example the three join algorithms. There are 81 possibilities to select one of the three algorithms for four different join operators. So, in the case of a five table join there are <span class=\"tt\">120 * 81 = 9720<\/span> different plans to consider. This does not even yet include things like index selection. You can see, the number of possible plans quickly gets too big for the optimizer to look at all of them.\n<\/p>\n<p>\nBecause of the high number of possible plans, the optimizer does not actually try to find the best plan. Instead it tries to find a good enough plan. To determine if it found a good enough plan, the optimizer looks at the cost estimate of the plans found so far and based on those estimates determines how long it is going to spend to find a better plan. After that time it takes the best plan it found up to then.\n<\/p>\n<p>\nThis is a very simplistic view of the things that happen during optimization. The point I am trying to make is that is it indeed very common for the optimizer to not find the best plan. However, most of the time the plan it comes up with is pretty close to the best. But every once in a while the execution plan that the optimizer came up with is really bad. In a case like that we can use query hints to help the optimizer find a better plan.\n<\/p>\n<h3>Join Hints<\/h3>\n<p>\nLet's look at this simple query:\n<\/p>\n<div>\n[sql]\nSELECT soh.AccountNumber, soh.OrderDate, sod.OrderQty, sod.UnitPrice<br \/>\nFROM Sales.SalesOrderDetail AS sod<br \/>\nINNER JOIN Sales.SalesOrderHeader AS soh<br \/>\nON soh.SalesOrderID = sod.SalesOrderID;<br \/>\n[\/sql]\n<\/div>\n<p>\nFor this query the optimizer decides to use a Merge Join operator:\n<\/p>\n<p>\n<a href=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-execution-plan.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-execution-plan.jpg\" alt=\"no hint execution plan\" title=\"no hint execution plan\" width=\"1093\" height=\"573\" class=\"aligncenter size-full wp-image-1447\" srcset=\"https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-execution-plan.jpg 1093w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-execution-plan-300x157.jpg 300w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-execution-plan-1024x536.jpg 1024w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-execution-plan-150x78.jpg 150w\" sizes=\"auto, (max-width: 1093px) 100vw, 1093px\" \/><\/a>\n<\/p>\n<p>\nThe Merge Join algorithm is actually the best choice in this context. But let's assume for this article that we know that another algorithm is better and we want to influence the optimizer's decision.\n<\/p>\n<p>\nThere are two ways to sway the optimizer to use a different join algorithm. The first one is a direct join hint and the second on is a query join hint. Both have in common, that they are not really hints, but they rather force the optimizer to use the specified algorithm.\n<\/p>\n<p>\nTo specify a direct join hint, we just need to mention the desired algorithm in between the word <span class=\"tt\">INNER<\/span> and the word <span class=\"tt\">JOIN<\/span> like this:\n<\/p>\n<p>\n<a href=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/inner-loop-join-hint-execution-plan.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/inner-loop-join-hint-execution-plan.jpg\" alt=\"inner loop join hint execution plan\" title=\"inner loop join hint execution plan\" width=\"1093\" height=\"573\" class=\"aligncenter size-full wp-image-1454\" srcset=\"https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/inner-loop-join-hint-execution-plan.jpg 1093w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/inner-loop-join-hint-execution-plan-300x157.jpg 300w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/inner-loop-join-hint-execution-plan-1024x536.jpg 1024w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/inner-loop-join-hint-execution-plan-150x78.jpg 150w\" sizes=\"auto, (max-width: 1093px) 100vw, 1093px\" \/><\/a>\n<\/p>\n<p>\nThe key word <span class=\"tt\">LOOP<\/span> causes the optimizer to us the Loop Join algorithm. If you want to specify the algorithm you have to type the <span class=\"tt\">INNER<\/span> key word as well. Just writing <span class=\"tt\">TblA LOOP JOIN TblB<\/span> will result in an error. However, when using an outer join, the hint can be placed right before the key word <span class=\"tt\">JOIN<\/span> and the key word <span class=\"tt\">OUTER<\/span> stays optional:\n<\/p>\n<p>\n<a href=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/left-hash-join-execution-plan.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/left-hash-join-execution-plan.jpg\" alt=\"left hash join execution plan\" title=\"left hash join execution plan\" width=\"1093\" height=\"573\" class=\"aligncenter size-full wp-image-1444\" srcset=\"https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/left-hash-join-execution-plan.jpg 1093w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/left-hash-join-execution-plan-300x157.jpg 300w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/left-hash-join-execution-plan-1024x536.jpg 1024w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/left-hash-join-execution-plan-150x78.jpg 150w\" sizes=\"auto, (max-width: 1093px) 100vw, 1093px\" \/><\/a>\n<\/p>\n<p>\nThis forces the Hash Join algorithm to be used in this Left Outer Join context.\n<\/p>\n<p>\nThe third algorithm is the Merge Join that the query used without a hint. You can force this algorithm with the key word <span class=\"tt\">MERGE<\/span>:\n<\/p>\n<p>\n<a href=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/inner-merge-join-execution-plan.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/inner-merge-join-execution-plan.jpg\" alt=\"inner merge join execution plan\" title=\"inner merge join execution plan\" width=\"1093\" height=\"573\" class=\"aligncenter size-full wp-image-1455\" srcset=\"https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/inner-merge-join-execution-plan.jpg 1093w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/inner-merge-join-execution-plan-300x157.jpg 300w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/inner-merge-join-execution-plan-1024x536.jpg 1024w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/inner-merge-join-execution-plan-150x78.jpg 150w\" sizes=\"auto, (max-width: 1093px) 100vw, 1093px\" \/><\/a>\n<\/p>\n<p>\nSo we would expect this to be the same execution plan as the one we got without the hint. But if you look closely, that is not the case. The order of the two inputs has been switched. The hint-free execution plan uses the <span class=\"tt\">Sales.SalesOrderHeader<\/span> table as first input and the <span class=\"tt\">Sales.SalesOrderDetail<\/span> table as second input. Because <span class=\"tt\">Sales.SalesOrderHeader<\/span> has less rows, that is the preferred order for almost all join situations. However, when hinting to the optimizer, which algorithm we want to use, we also force the order of the tables to stay the same as specified in the query.\n<\/p>\n<p>\nA hint specified like this affects only the join operator that it was specified at. You can specify a different algorithm for each join in the query. However, even a single join hint forces the order of the entire query.\n<\/p>\n<h3>Query Hints<\/h3>\n<p>\nThe second way to specify the desired join algorithm is a query hint. A query join hint is specified at the end of the query like this:\n<\/p>\n<p>\n<a href=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/option-loop-join-execution-plan.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/option-loop-join-execution-plan.jpg\" alt=\"option loop join execution plan\" title=\"option loop join execution plan\" width=\"1093\" height=\"573\" class=\"aligncenter size-full wp-image-1449\" srcset=\"https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/option-loop-join-execution-plan.jpg 1093w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/option-loop-join-execution-plan-300x157.jpg 300w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/option-loop-join-execution-plan-1024x536.jpg 1024w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/option-loop-join-execution-plan-150x78.jpg 150w\" sizes=\"auto, (max-width: 1093px) 100vw, 1093px\" \/><\/a>\n<\/p>\n<p>\nThis syntax also allows you to specify any of the three algorithms <span class=\"tt\">LOOP<\/span>, <span class=\"tt\">HASH<\/span> and <span class=\"tt\">MERGE<\/span>. There are two important differences between a query hint and a join hint. The first on is that a query hint does not force the table order as you can see in above example. The second difference is that the query hint forces all joins to use the same algorithm. Let's look at this query for an example:\n<\/p>\n<div>\n[sql]\nSELECT soh.AccountNumber, soh.OrderDate, sod.OrderQty, sod.UnitPrice, prod.Name<br \/>\nFROM Sales.SalesOrderDetail AS sod<br \/>\nINNER JOIN Sales.SalesOrderHeader AS soh<br \/>\nON soh.SalesOrderID = sod.SalesOrderID<br \/>\nINNER JOIN Production.Product AS prod<br \/>\nON sod.ProductID = prod.ProductID;<br \/>\n[\/sql]\n<\/div>\n<p>\nIf un-hinted like above, it results in this execution plan:\n<\/p>\n<p>\n<a href=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-multi-join-example.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-multi-join-example.jpg\" alt=\"no hint multi-join execution plan\" title=\"no hint multi-join execution plan\" width=\"1093\" height=\"573\" class=\"aligncenter size-full wp-image-1448\" srcset=\"https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-multi-join-example.jpg 1093w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-multi-join-example-300x157.jpg 300w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-multi-join-example-1024x536.jpg 1024w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-multi-join-example-150x78.jpg 150w\" sizes=\"auto, (max-width: 1093px) 100vw, 1093px\" \/><\/a>\n<\/p>\n<p>\nNow let's specify just a single join hint:\n<\/p>\n<div>\n[sql]\nSELECT soh.AccountNumber, soh.OrderDate, sod.OrderQty, sod.UnitPrice, prod.Name<br \/>\nFROM Sales.SalesOrderDetail AS sod<br \/>\nINNER JOIN Sales.SalesOrderHeader AS soh<br \/>\nON soh.SalesOrderID = sod.SalesOrderID<br \/>\nINNER LOOP JOIN Production.Product AS prod<br \/>\nON sod.ProductID = prod.ProductID;<br \/>\n[\/sql]\n<\/div>\n<p>\nThis forces only the second join to be a loop join. The first join is now replaced by a hash join.\n<\/p>\n<p>\n<a href=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/single-inner-loop-join-execution-plan.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/single-inner-loop-join-execution-plan.jpg\" alt=\"single inner loop join hint execution plan\" title=\"single inner loop join hint execution plan\" width=\"1093\" height=\"573\" class=\"aligncenter size-full wp-image-1451\" srcset=\"https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/single-inner-loop-join-execution-plan.jpg 1093w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/single-inner-loop-join-execution-plan-300x157.jpg 300w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/single-inner-loop-join-execution-plan-1024x536.jpg 1024w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/single-inner-loop-join-execution-plan-150x78.jpg 150w\" sizes=\"auto, (max-width: 1093px) 100vw, 1093px\" \/><\/a>\n<\/p>\n<p>\nYou can also see that the order in which the tables are accessed now matches the order in which they are mentioned in the query.\n<\/p>\n<p>\nNow let's look at this query with a query hint:\n<\/p>\n<div>\n[sql]\nSELECT soh.AccountNumber, soh.OrderDate, sod.OrderQty, sod.UnitPrice, prod.Name<br \/>\nFROM Sales.SalesOrderDetail AS sod<br \/>\nINNER JOIN Sales.SalesOrderHeader AS soh<br \/>\nON soh.SalesOrderID = sod.SalesOrderID<br \/>\nINNER JOIN Production.Product AS prod<br \/>\nON sod.ProductID = prod.ProductID<br \/>\nOPTION(LOOP JOIN);<br \/>\n[\/sql]\n<\/div>\n<p>\nNow both join operators are using the Loop Join algorithm:\n<\/p>\n<p>\n<a href=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/loop-join-query-hint-execution-plan.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/loop-join-query-hint-execution-plan.jpg\" alt=\"loop join query hint execution plan\" title=\"loop join query hint execution plan\" width=\"1093\" height=\"573\" class=\"aligncenter size-full wp-image-1445\" srcset=\"https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/loop-join-query-hint-execution-plan.jpg 1093w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/loop-join-query-hint-execution-plan-300x157.jpg 300w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/loop-join-query-hint-execution-plan-1024x536.jpg 1024w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/loop-join-query-hint-execution-plan-150x78.jpg 150w\" sizes=\"auto, (max-width: 1093px) 100vw, 1093px\" \/><\/a>\n<\/p>\n<p>\nHowever, the table order does not match the one specified in the query.\n<\/p>\n<p>\nThe two types of hints cannot be mixed. If you attempt to do so error 1042 will be raised:\n<\/p>\n<p>\n<a href=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/mixed-hints-error.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/mixed-hints-error.jpg\" alt=\"error when mixing hints\" title=\"error when mixing hints\" width=\"1093\" height=\"573\" class=\"aligncenter size-full wp-image-1446\" srcset=\"https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/mixed-hints-error.jpg 1093w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/mixed-hints-error-300x157.jpg 300w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/mixed-hints-error-1024x536.jpg 1024w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/mixed-hints-error-150x78.jpg 150w\" sizes=\"auto, (max-width: 1093px) 100vw, 1093px\" \/><\/a>\n<\/p>\n<h3>FORCE ORDER<\/h3>\n<p>\nIf you just want to force the order of the tables without specifying the algorithm(s) to be used, there is a<del>n app<\/del> <ins>hint<\/ins> for that too:\n<\/p>\n<div>\n[sql]\nSELECT soh.AccountNumber, soh.OrderDate, sod.OrderQty, sod.UnitPrice, prod.Name<br \/>\nFROM Sales.SalesOrderDetail AS sod<br \/>\nINNER JOIN Sales.SalesOrderHeader AS soh<br \/>\nON soh.SalesOrderID = sod.SalesOrderID<br \/>\nINNER JOIN Production.Product AS prod<br \/>\nON sod.ProductID = prod.ProductID<br \/>\nOPTION(FORCE ORDER);<br \/>\n[\/sql]\n<\/div>\n<p>\nThe <span class=\"tt\">FORCE ORDER<\/span> query hint gives us just that functionality. It forces the order but still allows the optimizer to choose the algorithms that it finds most appropriate.\n<\/p>\n<p>\n<a href=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/force-order-execution-plan.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/force-order-execution-plan.jpg\" alt=\"force order execution plan\" title=\"force order execution plan\" width=\"1093\" height=\"573\" class=\"aligncenter size-full wp-image-1453\" srcset=\"https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/force-order-execution-plan.jpg 1093w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/force-order-execution-plan-300x157.jpg 300w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/force-order-execution-plan-1024x536.jpg 1024w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/force-order-execution-plan-150x78.jpg 150w\" sizes=\"auto, (max-width: 1093px) 100vw, 1093px\" \/><\/a>\n<\/p>\n<p>\n <span class=\"tt\">FORCE ORDER<\/span> actually does not only consider the order of tables in the query, but also the placement of the <span class=\"tt\">ON<\/span> clauses. For an example let's look at this slightly modified query:\n<\/p>\n<div>\n[sql]\nSELECT soh.AccountNumber, soh.OrderDate, sod.OrderQty, sod.UnitPrice,pers.FirstName, pers.LastName<br \/>\nFROM    (<br \/>\n        Sales.SalesOrderHeader AS soh<br \/>\n        INNER JOIN Sales.SalesOrderDetail AS sod<br \/>\n          ON soh.SalesOrderID = sod.SalesOrderID<br \/>\n        )<br \/>\nINNER JOIN (<br \/>\n        Sales.Customer AS cust<br \/>\n        INNER JOIN Person.Person AS pers<br \/>\n          ON cust.PersonID = pers.BusinessEntityID<br \/>\n        )<br \/>\n        ON soh.CustomerID = cust.CustomerID;<br \/>\n[\/sql]\n<\/div>\n<p>\nWithout a join or table hint we get this right deep execution plan:\n<\/p>\n<p>\n<a href=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/right-deep-no-hint-execution-plan.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/right-deep-no-hint-execution-plan.jpg\" alt=\"right deep execution plan with no hints\" title=\"right deep execution plan with no hints\" width=\"1920\" height=\"1138\" class=\"aligncenter size-full wp-image-1450\" srcset=\"https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/right-deep-no-hint-execution-plan.jpg 1920w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/right-deep-no-hint-execution-plan-300x177.jpg 300w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/right-deep-no-hint-execution-plan-1024x606.jpg 1024w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/right-deep-no-hint-execution-plan-150x88.jpg 150w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><\/a>\n<\/p>\n<p>\nHowever, if we add the <span class=\"tt\">FORCE ORDER<\/span> hint the optimizer builds a bushy execution plan in which first the <span class=\"tt\">Sales.SalesOrderHeader<\/span> and <span class=\"tt\">Sales.SalesOrderDetail<\/span> tables are joined, then the <span class=\"tt\">Sales.Customer<\/span> and <span class=\"tt\">Person.Person<\/span> tables and finally the two results with each outher:\n<\/p>\n<p>\n<a href=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/bushy-force-order-execution-plan.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/bushy-force-order-execution-plan.jpg\" alt=\"force order hint leading to bushy execution plan\" title=\"force order hint leading to bushy execution plan\" width=\"1920\" height=\"1138\" class=\"aligncenter size-full wp-image-1452\" srcset=\"https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/bushy-force-order-execution-plan.jpg 1920w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/bushy-force-order-execution-plan-300x177.jpg 300w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/bushy-force-order-execution-plan-1024x606.jpg 1024w, https:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/bushy-force-order-execution-plan-150x88.jpg 150w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><\/a>\n<\/p>\n<p>\nThere are a few additional options available for join and query hints that we can't discuss today. Check out these two Books Online articles for more information:<br \/>\n<br \/><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms173815.aspx\">http:\/\/msdn.microsoft.com\/en-us\/library\/ms173815.aspx<\/a><br \/>\n<br \/><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms181714.aspx\">http:\/\/msdn.microsoft.com\/en-us\/library\/ms181714.aspx<\/a>\n<\/p>\n<h3>Cautionary Hint<\/h3>\n<p>\nWorking with hints in T-SQL is always a double edged sword. While you might find a better table order or set of algorithms for a particular query base on the current data, you are taking away SQL Servers ability to adapt to changes in the data. Every time enough data in one of the tables has changed SQL Server (with default options enabled) will revisit every query accessing that table to see if it can come up with a better plan. It cannot do that with queries on which you have forced its way. For that reason it is an accepted best practice to use any type of query hint only after all other options failed.\n<\/p>\n<p>\nIf you have a join query that needs some performance improvements, the first thing to check is if appropriate indexes exist and if the query is written in a way that those indexes can actually be used. If that does not help, make sure that all statistics are up to date. Finally you could check if adding additional statistics or filtered statistics can improve the query.\n<\/p>\n<p>\nThis list is not meant to be exhaustive. It just gives you a starting point for things to look at when trying to improve the performance of a join query.\n<\/p>\n<h3>Summary<\/h3>\n<p>\nJoin hints are a very powerful way to steer the decisions of the optimizer that affect join algorithm selection and table access order. We have seen several options to influence those decisions. However, every time we hint to the optimizer, we take some of its flexibility to adapt to changes in the data away. While a hinted query might be smooth sailing today, be aware of what comes after the next wave of updates to your data.\n<\/p>\n<h3>A Join A Day<\/h3>\n<p>\nThis post is part of my December 2012 \"A Join A Day\" blog post series. You can find the table of contents with all posts published so far in the introductory post: <a href=\"http:\/\/sqlity.net\/en\/1146\/a-join-a-day-introduction\/\">A Join A Day \u2013 Introduction<\/a>. Check back there frequently throughout the month.\n<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>SQL Server cannot do an exhaustive search of all possible execution plans when compiling a query. On its quest to find the best plan, it sometimes misses the mark. See how join hints and query hints can help in a situation like that. But be aware, using join hints can backfire. Know the risks before you start using them.<\/p>\n<p> <a href=\"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/\">[more&#8230;]<\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[28,29,5,30,19,27],"tags":[],"class_list":["post-1443","post","type-post","status-publish","format-standard","hentry","category-a-join-a-day","category-fundamentals","category-general","category-hints","category-performance","category-series"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>A Join A Day \u2013 Join Hints - sqlity.net<\/title>\n<meta name=\"description\" content=\"SQL Server cannot do an exhaustive search of all possible execution plans when compiling a query. On its quest to find the best plan, it sometimes misses the mark. See how join hints and query hints can help in a situation like that. But be aware, using join hints can backfire. Know the risks before you start using them.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"A Join A Day \u2013 Join Hints - sqlity.net\" \/>\n<meta property=\"og:description\" content=\"SQL Server cannot do an exhaustive search of all possible execution plans when compiling a query. On its quest to find the best plan, it sometimes misses the mark. See how join hints and query hints can help in a situation like that. But be aware, using join hints can backfire. Know the risks before you start using them.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/\" \/>\n<meta property=\"og:site_name\" content=\"sqlity.net\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/sqlity.net\" \/>\n<meta property=\"article:published_time\" content=\"2012-12-20T15:00:43+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2014-11-13T18:50:40+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-execution-plan.jpg\" \/>\n<meta name=\"author\" content=\"Sebastian Meine\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@sqlity\" \/>\n<meta name=\"twitter:site\" content=\"@sqlity\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Sebastian Meine\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1443\\\/a-join-a-day-join-hints\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1443\\\/a-join-a-day-join-hints\\\/\"},\"author\":{\"name\":\"Sebastian Meine\",\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/#\\\/schema\\\/person\\\/bcffd8c572bc2f1bd10fdba80135e53c\"},\"headline\":\"A Join A Day \u2013 Join Hints\",\"datePublished\":\"2012-12-20T15:00:43+00:00\",\"dateModified\":\"2014-11-13T18:50:40+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1443\\\/a-join-a-day-join-hints\\\/\"},\"wordCount\":1800,\"commentCount\":1,\"image\":{\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1443\\\/a-join-a-day-join-hints\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/sqlity.net\\\/wp-content\\\/uploads\\\/2012\\\/12\\\/no-hint-execution-plan.jpg\",\"articleSection\":[\"A Join A Day\",\"Fundamentals\",\"General\",\"Hints\",\"Performance\",\"Series\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/sqlity.net\\\/en\\\/1443\\\/a-join-a-day-join-hints\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1443\\\/a-join-a-day-join-hints\\\/\",\"url\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1443\\\/a-join-a-day-join-hints\\\/\",\"name\":\"A Join A Day \u2013 Join Hints - sqlity.net\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1443\\\/a-join-a-day-join-hints\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1443\\\/a-join-a-day-join-hints\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/sqlity.net\\\/wp-content\\\/uploads\\\/2012\\\/12\\\/no-hint-execution-plan.jpg\",\"datePublished\":\"2012-12-20T15:00:43+00:00\",\"dateModified\":\"2014-11-13T18:50:40+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/#\\\/schema\\\/person\\\/bcffd8c572bc2f1bd10fdba80135e53c\"},\"description\":\"SQL Server cannot do an exhaustive search of all possible execution plans when compiling a query. On its quest to find the best plan, it sometimes misses the mark. See how join hints and query hints can help in a situation like that. But be aware, using join hints can backfire. Know the risks before you start using them.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1443\\\/a-join-a-day-join-hints\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/sqlity.net\\\/en\\\/1443\\\/a-join-a-day-join-hints\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1443\\\/a-join-a-day-join-hints\\\/#primaryimage\",\"url\":\"http:\\\/\\\/sqlity.net\\\/wp-content\\\/uploads\\\/2012\\\/12\\\/no-hint-execution-plan.jpg\",\"contentUrl\":\"http:\\\/\\\/sqlity.net\\\/wp-content\\\/uploads\\\/2012\\\/12\\\/no-hint-execution-plan.jpg\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/1443\\\/a-join-a-day-join-hints\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/sqlity.net\\\/en\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"A Join A Day \u2013 Join Hints\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/#website\",\"url\":\"https:\\\/\\\/sqlity.net\\\/en\\\/\",\"name\":\"sqlity.net\",\"description\":\"Quality for SQL\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/sqlity.net\\\/en\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/sqlity.net\\\/en\\\/#\\\/schema\\\/person\\\/bcffd8c572bc2f1bd10fdba80135e53c\",\"name\":\"Sebastian Meine\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4ab0a6d02dd494849a584a2c3c8bc3bdcef1d0aa5f87e98bf905dbdb9ad2ce3a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4ab0a6d02dd494849a584a2c3c8bc3bdcef1d0aa5f87e98bf905dbdb9ad2ce3a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/4ab0a6d02dd494849a584a2c3c8bc3bdcef1d0aa5f87e98bf905dbdb9ad2ce3a?s=96&d=mm&r=g\",\"caption\":\"Sebastian Meine\"},\"sameAs\":[\"http:\\\/\\\/sqlity.net\",\"https:\\\/\\\/x.com\\\/sqlity\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"A Join A Day \u2013 Join Hints - sqlity.net","description":"SQL Server cannot do an exhaustive search of all possible execution plans when compiling a query. On its quest to find the best plan, it sometimes misses the mark. See how join hints and query hints can help in a situation like that. But be aware, using join hints can backfire. Know the risks before you start using them.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/","og_locale":"en_US","og_type":"article","og_title":"A Join A Day \u2013 Join Hints - sqlity.net","og_description":"SQL Server cannot do an exhaustive search of all possible execution plans when compiling a query. On its quest to find the best plan, it sometimes misses the mark. See how join hints and query hints can help in a situation like that. But be aware, using join hints can backfire. Know the risks before you start using them.","og_url":"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/","og_site_name":"sqlity.net","article_publisher":"https:\/\/www.facebook.com\/sqlity.net","article_published_time":"2012-12-20T15:00:43+00:00","article_modified_time":"2014-11-13T18:50:40+00:00","og_image":[{"url":"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-execution-plan.jpg","type":"","width":"","height":""}],"author":"Sebastian Meine","twitter_card":"summary_large_image","twitter_creator":"@sqlity","twitter_site":"@sqlity","twitter_misc":{"Written by":"Sebastian Meine","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/#article","isPartOf":{"@id":"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/"},"author":{"name":"Sebastian Meine","@id":"https:\/\/sqlity.net\/en\/#\/schema\/person\/bcffd8c572bc2f1bd10fdba80135e53c"},"headline":"A Join A Day \u2013 Join Hints","datePublished":"2012-12-20T15:00:43+00:00","dateModified":"2014-11-13T18:50:40+00:00","mainEntityOfPage":{"@id":"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/"},"wordCount":1800,"commentCount":1,"image":{"@id":"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/#primaryimage"},"thumbnailUrl":"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-execution-plan.jpg","articleSection":["A Join A Day","Fundamentals","General","Hints","Performance","Series"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/","url":"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/","name":"A Join A Day \u2013 Join Hints - sqlity.net","isPartOf":{"@id":"https:\/\/sqlity.net\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/#primaryimage"},"image":{"@id":"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/#primaryimage"},"thumbnailUrl":"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-execution-plan.jpg","datePublished":"2012-12-20T15:00:43+00:00","dateModified":"2014-11-13T18:50:40+00:00","author":{"@id":"https:\/\/sqlity.net\/en\/#\/schema\/person\/bcffd8c572bc2f1bd10fdba80135e53c"},"description":"SQL Server cannot do an exhaustive search of all possible execution plans when compiling a query. On its quest to find the best plan, it sometimes misses the mark. See how join hints and query hints can help in a situation like that. But be aware, using join hints can backfire. Know the risks before you start using them.","breadcrumb":{"@id":"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/#primaryimage","url":"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-execution-plan.jpg","contentUrl":"http:\/\/sqlity.net\/wp-content\/uploads\/2012\/12\/no-hint-execution-plan.jpg"},{"@type":"BreadcrumbList","@id":"https:\/\/sqlity.net\/en\/1443\/a-join-a-day-join-hints\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/sqlity.net\/en\/"},{"@type":"ListItem","position":2,"name":"A Join A Day \u2013 Join Hints"}]},{"@type":"WebSite","@id":"https:\/\/sqlity.net\/en\/#website","url":"https:\/\/sqlity.net\/en\/","name":"sqlity.net","description":"Quality for SQL","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/sqlity.net\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/sqlity.net\/en\/#\/schema\/person\/bcffd8c572bc2f1bd10fdba80135e53c","name":"Sebastian Meine","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/4ab0a6d02dd494849a584a2c3c8bc3bdcef1d0aa5f87e98bf905dbdb9ad2ce3a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/4ab0a6d02dd494849a584a2c3c8bc3bdcef1d0aa5f87e98bf905dbdb9ad2ce3a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/4ab0a6d02dd494849a584a2c3c8bc3bdcef1d0aa5f87e98bf905dbdb9ad2ce3a?s=96&d=mm&r=g","caption":"Sebastian Meine"},"sameAs":["http:\/\/sqlity.net","https:\/\/x.com\/sqlity"]}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2wXuw-nh","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/posts\/1443","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/comments?post=1443"}],"version-history":[{"count":0,"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/posts\/1443\/revisions"}],"wp:attachment":[{"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/media?parent=1443"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/categories?post=1443"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sqlity.net\/en\/wp-json\/wp\/v2\/tags?post=1443"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}