{"id":951,"date":"2018-10-03T11:26:04","date_gmt":"2018-10-03T18:26:04","guid":{"rendered":"http:\/\/3.209.169.194\/blogs\/erin\/?p=951"},"modified":"2019-03-04T10:58:27","modified_gmt":"2019-03-04T18:58:27","slug":"plan-forcing-in-sql-server","status":"publish","type":"post","link":"https:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/","title":{"rendered":"Plan Forcing in SQL Server"},"content":{"rendered":"<p>Last month I was in Portugal for their SQLSaturday event, and I spent a lot of time talking about Plan Forcing in SQL Server \u2013 both manual and automatic (via the Automatic Plan Correction feature). I had some really great questions from my pre-con and regular session and wanted to summarize a few thoughts on Plan Forcing functionality.<\/p>\n<p>Forcing plans in SQL Server provides a very easy method for DBAs and developers to stabilize query performance.\u00a0 <strong>But plan forcing is not a permanent solution.<\/strong>\u00a0 Consider the premise on which plan forcing relies: multiple plans exist for a query and one of them provides the most consistent performance.\u00a0 If I have high variability in query performance, ideally, I want to address that in the code or through schema changes (e.g. indexing).\u00a0 Forcing a plan for a query is a lot like creating a plan guide \u2013 <em>they are similar but they are two separate features<\/em> \u2013 in that it\u2019s a temporary solution.\u00a0 I also view adding OPTION (RECOMPILE) as a temporary solution. Some of you might be shocked at that, but when I see a RECOMPILE on a query, I immediately ask <strong>why<\/strong> it was added, <strong>when<\/strong> it was added, and I start looking at what can be done to remove it.<\/p>\n<p>Knowing that this is how I view plan forcing, how do I decide when to force a plan? \u00a0When the query has variability in performance.<\/p>\n<p>Consider Query A, which generates multiple plans, but they\u2019re all about the same in terms of duration, I\/O, and CPU.\u00a0 The performance across the different plans is consistent.\u00a0 I won\u2019t force a plan for that query.<\/p>\n<figure id=\"attachment_953\" aria-describedby=\"caption-attachment-953\" style=\"width: 1024px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-content\/uploads\/2018\/10\/stable.png\"><img fetchpriority=\"high\" decoding=\"async\" class=\"wp-image-953 size-large\" src=\"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-content\/uploads\/2018\/10\/stable-1024x322.png\" alt=\"Query with multiple, consistent plans\" width=\"1024\" height=\"322\" srcset=\"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-content\/uploads\/2018\/10\/stable-1024x322.png 1024w, https:\/\/www.sqlskills.com\/blogs\/erin\/wp-content\/uploads\/2018\/10\/stable-300x94.png 300w, https:\/\/www.sqlskills.com\/blogs\/erin\/wp-content\/uploads\/2018\/10\/stable-900x283.png 900w, https:\/\/www.sqlskills.com\/blogs\/erin\/wp-content\/uploads\/2018\/10\/stable.png 1641w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption id=\"caption-attachment-953\" class=\"wp-caption-text\">Query with multiple, consistent plans<\/figcaption><\/figure>\n<p>Next consider Query B, which also generates different plans, and some are stable but a couple are over the place in terms of duration, I\/O, and CPU.\u00a0 Maybe a couple plans provide good performance, but the rest are awful.\u00a0 Would I force one of the \u201cgood plans\u201d?\u00a0 Probably \u2013 but I\u2019d do some testing first.<\/p>\n<figure id=\"attachment_954\" aria-describedby=\"caption-attachment-954\" style=\"width: 1024px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-content\/uploads\/2018\/10\/multiple.png\"><img decoding=\"async\" class=\"size-large wp-image-954\" src=\"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-content\/uploads\/2018\/10\/multiple-1024x328.png\" alt=\"Query with multiple plans that have variable performance\" width=\"1024\" height=\"328\" srcset=\"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-content\/uploads\/2018\/10\/multiple-1024x328.png 1024w, https:\/\/www.sqlskills.com\/blogs\/erin\/wp-content\/uploads\/2018\/10\/multiple-300x96.png 300w, https:\/\/www.sqlskills.com\/blogs\/erin\/wp-content\/uploads\/2018\/10\/multiple-900x289.png 900w, https:\/\/www.sqlskills.com\/blogs\/erin\/wp-content\/uploads\/2018\/10\/multiple.png 1609w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption id=\"caption-attachment-954\" class=\"wp-caption-text\">Query with multiple plans that have variable performance<\/figcaption><\/figure>\n<p>Understand that if I force a plan for a query, that\u2019s the plan that\u2019s going to get used unless forcing fails for some reason (e.g. the index no longer exists).\u00a0 But does that plan work for all variations of the query?\u00a0 Does that plan provide consistent performance for all the different input parameters that can be used for that query?\u00a0 This requires testing\u2026and oh by the way, concurrent with any testing\/decision to force a plan I\u2019m talking to the developers about ways to address this long-term.<\/p>\n<p>Now, out of my entire workload, if I have many queries that have multiple plans, where do I start?\u00a0 With the worst offenders.\u00a0 If I\u2019m resource-bound in some way (e.g. CPU or I\/O), then I would look at queries with the highest resource use and start working through those.\u00a0 But I also look for the \u201cdeath by a thousand cuts\u201d scenario \u2013 the queries which execute hundreds or thousands of times a minute.\u00a0 <em>As an aside, during the pre-con in Portugal one of the attendees had me look at a query in Query Store in the production environment.\u00a0 There was concern because the query had multiple plans.\u00a0 I pointed out that the query had executed 71,000 times in an hour\u2026which is almost 20 times a second.\u00a0 While I want to investigate multiple plans, I also want to know why a query executes so often.<\/em><\/p>\n<p>Thus far, I\u2019ve talked about a workload\u2026<strong>one workload<\/strong>.\u00a0 What about the environment where you support hundreds of SQL Server instances?\u00a0 You can obviously take the approach I\u2019ve detailed above, which requires a review of poor-performing queries with multiple plans and deciding which plan (if any) to force until development addresses the issue.\u00a0 Or, if you\u2019re running SQL Server 2017 Enterprise Edition, you could look at Automatic Plan Correction, which will force a plan for a query (without human intervention) if there\u2019s a regression.\u00a0 I wrote a post (<a href=\"https:\/\/sqlperformance.com\/2018\/02\/sql-plan\/automatic-plan-correction-in-sql-server\">Automatic Plan Correction in SQL Server<\/a>) on SQLPerformance.com about this feature, so I\u2019m not going to re-hash the details here.<\/p>\n<p>Whether you force plans manually, or let SQL Server force them with the Automatic Plan Correction feature, I still view plan forcing as a <em>temporary solution<\/em>.\u00a0 I don\u2019t expect you to have plans forced for years, let alone months.\u00a0 The life of a forced plan will, of course, depend on how quickly code and schema changes are ported to production.\u00a0 If you go the &#8220;set it and forget it route&#8221;, theoretically a manually forced plan could get used for a very long time.\u00a0 In that scenario, it\u2019s <strong>your<\/strong> responsibility to periodically check to ensure that plan is still the \u201cbest\u201d one for the query.\u00a0 I would be checking every couple weeks; once a month at most.\u00a0 Whether or not the plan remains optimal depends on the tables involved in the query, the data in the tables, how that data changes (if it changes), other schema changes that may be introduced, and more.<\/p>\n<p>Further, you don\u2019t want to ignore forced plans because there are cases where a forced plan won\u2019t be used (you can use Extended Events to monitor this).\u00a0 When you force a plan manually, forcing can still fail.\u00a0 For example, if the forced plan uses an index and the index is dropped, or its definition is changed to the point where it cannot be used in plan in the same manner, then forcing will fail. \u00a0<em>Important note: if forcing fails, the query will go through normal optimization and compilation and it will execute; SQL Server does not want your query to fail!<\/em>\u00a0 If you\u2019re forcing plans and not familiar with the reasons that it can fail, note the last_force_failure_reason values listed for <a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/relational-databases\/system-catalog-views\/sys-query-store-plan-transact-sql?view=sql-server-2017\">sys.query_store_plan<\/a>.\u00a0 If you have manually forced a plan for a query, and the force plan fails, it remains forced.\u00a0 You have to manually un-force it to stop SQL Server from trying to use that plan.\u00a0 As you can see, there are <strong>multiple<\/strong> factors related to plan forcing, which is why you don\u2019t just force a plan and forget it.<\/p>\n<p>This behavior is different if you\u2019re using Automatic Plan Correction (APC).\u00a0 As mentioned in the <a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/relational-databases\/automatic-tuning\/automatic-tuning?view=sql-server-2017\">Automatic tuning documentation<\/a>, if a plan is automatically forced, it will be automatically un-forced if:<\/p>\n<ul>\n<li>forcing fails for any reason<\/li>\n<li>if there is a performance regression using the forced plan<\/li>\n<li>if there is a recompile due to a schema change or an update to statistics.<\/li>\n<\/ul>\n<p>With APC, there is still work to be done &#8211; here you want to use Extended Events or sys.dm_db_tuning_recommendations to see what plans are getting forced, and then decide if you want to force them manually.\u00a0 <em>If you force a plan manually it will never be automatically un-forced.<\/em><\/p>\n<p>There are a lot of considerations when you embrace plan forcing &#8211; I think it&#8217;s an excellent alternative to plan guides (much easier to use, not schema bound) and I think it&#8217;s absolutely worth a DBA or developer&#8217;s time to investigate what plan to force, and then use that as a temporary solution until a long-term fix can be put in place.\u00a0 I hope this helps those of you that have been wary to give it a try!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last month I was in Portugal for their SQLSaturday event, and I spent a lot of time talking about Plan Forcing in SQL Server \u2013 both manual and automatic (via the Automatic Plan Correction feature). I had some really great questions from my pre-con and regular session and wanted to summarize a few thoughts on [&hellip;]<\/p>\n","protected":false},"author":7,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[50,46],"tags":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v21.9.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Plan Forcing in SQL Server - Erin Stellato<\/title>\n<meta name=\"description\" content=\"Plan Forcing in SQL Server is part of the Query Store feature and very easy to use, but there are a few things to understand if you&#039;re using it!\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Plan Forcing in SQL Server - Erin Stellato\" \/>\n<meta property=\"og:description\" content=\"Plan Forcing in SQL Server is part of the Query Store feature and very easy to use, but there are a few things to understand if you&#039;re using it!\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/\" \/>\n<meta property=\"og:site_name\" content=\"Erin Stellato\" \/>\n<meta property=\"article:published_time\" content=\"2018-10-03T18:26:04+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-03-04T18:58:27+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-content\/uploads\/2018\/10\/stable-1024x322.png\" \/>\n<meta name=\"author\" content=\"Erin Stellato\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Erin Stellato\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/\",\"name\":\"Plan Forcing in SQL Server - Erin Stellato\",\"isPartOf\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/erin\/#website\"},\"datePublished\":\"2018-10-03T18:26:04+00:00\",\"dateModified\":\"2019-03-04T18:58:27+00:00\",\"author\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/erin\/#\/schema\/person\/76170223ffffa1df03fd9be5b66cb158\"},\"description\":\"Plan Forcing in SQL Server is part of the Query Store feature and very easy to use, but there are a few things to understand if you're using it!\",\"breadcrumb\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.sqlskills.com\/blogs\/erin\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Plan Forcing in SQL Server\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/erin\/#website\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/erin\/\",\"name\":\"Erin Stellato\",\"description\":\"The SQL Sequel\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.sqlskills.com\/blogs\/erin\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/erin\/#\/schema\/person\/76170223ffffa1df03fd9be5b66cb158\",\"name\":\"Erin Stellato\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/erin\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/0c8b485bd54ea26b57e99f79b525f409?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/0c8b485bd54ea26b57e99f79b525f409?s=96&d=mm&r=g\",\"caption\":\"Erin Stellato\"},\"sameAs\":[\"http:\/\/3.209.169.194\/blogs\/erin\"],\"url\":\"https:\/\/www.sqlskills.com\/blogs\/erin\/author\/erin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Plan Forcing in SQL Server - Erin Stellato","description":"Plan Forcing in SQL Server is part of the Query Store feature and very easy to use, but there are a few things to understand if you're using it!","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:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/","og_locale":"en_US","og_type":"article","og_title":"Plan Forcing in SQL Server - Erin Stellato","og_description":"Plan Forcing in SQL Server is part of the Query Store feature and very easy to use, but there are a few things to understand if you're using it!","og_url":"https:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/","og_site_name":"Erin Stellato","article_published_time":"2018-10-03T18:26:04+00:00","article_modified_time":"2019-03-04T18:58:27+00:00","og_image":[{"url":"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-content\/uploads\/2018\/10\/stable-1024x322.png"}],"author":"Erin Stellato","twitter_misc":{"Written by":"Erin Stellato","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/","url":"https:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/","name":"Plan Forcing in SQL Server - Erin Stellato","isPartOf":{"@id":"https:\/\/www.sqlskills.com\/blogs\/erin\/#website"},"datePublished":"2018-10-03T18:26:04+00:00","dateModified":"2019-03-04T18:58:27+00:00","author":{"@id":"https:\/\/www.sqlskills.com\/blogs\/erin\/#\/schema\/person\/76170223ffffa1df03fd9be5b66cb158"},"description":"Plan Forcing in SQL Server is part of the Query Store feature and very easy to use, but there are a few things to understand if you're using it!","breadcrumb":{"@id":"https:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.sqlskills.com\/blogs\/erin\/plan-forcing-in-sql-server\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.sqlskills.com\/blogs\/erin\/"},{"@type":"ListItem","position":2,"name":"Plan Forcing in SQL Server"}]},{"@type":"WebSite","@id":"https:\/\/www.sqlskills.com\/blogs\/erin\/#website","url":"https:\/\/www.sqlskills.com\/blogs\/erin\/","name":"Erin Stellato","description":"The SQL Sequel","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.sqlskills.com\/blogs\/erin\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.sqlskills.com\/blogs\/erin\/#\/schema\/person\/76170223ffffa1df03fd9be5b66cb158","name":"Erin Stellato","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.sqlskills.com\/blogs\/erin\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/0c8b485bd54ea26b57e99f79b525f409?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/0c8b485bd54ea26b57e99f79b525f409?s=96&d=mm&r=g","caption":"Erin Stellato"},"sameAs":["http:\/\/3.209.169.194\/blogs\/erin"],"url":"https:\/\/www.sqlskills.com\/blogs\/erin\/author\/erin\/"}]}},"_links":{"self":[{"href":"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-json\/wp\/v2\/posts\/951"}],"collection":[{"href":"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-json\/wp\/v2\/comments?post=951"}],"version-history":[{"count":0,"href":"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-json\/wp\/v2\/posts\/951\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-json\/wp\/v2\/media?parent=951"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-json\/wp\/v2\/categories?post=951"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/erin\/wp-json\/wp\/v2\/tags?post=951"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}