{"id":24265,"date":"2023-04-10T07:00:00","date_gmt":"2023-04-10T05:00:00","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/?p=24265"},"modified":"2025-10-01T12:10:55","modified_gmt":"2025-10-01T10:10:55","slug":"sql-server-how-correlation-assumptions-work-for-multiple-predicates","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/","title":{"rendered":"SQL Server: How Correlation assumptions work for multiple predicates"},"content":{"rendered":"\n<p>SQL Server 2022 introduced &#8220;<a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/performance\/intelligent-query-processing-feedback?view=sql-server-ver16#cardinality-estimation-ce-feedback\">CE Feedback<\/a>&#8220;, a feature that adjusts some Cardinality Estimation model assumptions at a query level by applying <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/performance\/query-store-hints?view=sql-server-ver16\" target=\"_blank\" rel=\"noreferrer noopener\">Query Store hints<\/a>.<\/p>\n\n\n\n<p>In this blog post, I&#8217;ll use an example query from the CE Feedback documentation to look in more detail at how CE works. The goal is to better understand how SQL Server uses certain assumptions to estimate the number of rows to process based on statistics.<\/p>\n\n\n\n<p>I will not give an introduction to cardinality estimation in this post. I will simply refer you to the documentation: <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/performance\/cardinality-estimation-sql-server?view=sql-server-ver16#versions-of-the-ce\" target=\"_blank\" rel=\"noreferrer noopener\">Cardinality Estimation (SQL Server)<\/a>.<\/p>\n\n\n\n<p>Let&#8217;s just say that Cardinality Estimation is how the Query Optimizer can estimate the number of rows processed by an execution plan. Cardinality estimation is derived primarily from <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/statistics\/statistics?view=sql-server-ver16\" target=\"_blank\" rel=\"noreferrer noopener\">statistics<\/a>. With more accurate estimations, the Query Optimizer can usually do a better job of producing a good query plan.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-sql-server-2022-ce-feedback-demo\">SQL Server 2022 CE Feedback demo<\/h2>\n\n\n\n<p>The query that I will use for this blog post is provided in the <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/performance\/intelligent-query-processing-feedback?view=sql-server-ver16#ce-feedback-scenarios\" target=\"_blank\" rel=\"noreferrer noopener\">CE feedback scenarios<\/a> documentation and is also used by Bob Ward in his SQL Server 2022 demos. See <a href=\"https:\/\/github.com\/microsoft\/bobsql\/tree\/master\/demos\/sqlserver2022\/IQP\/cefeedback\" target=\"_blank\" rel=\"noreferrer noopener\">Demo for CE Feedback for SQL Server 2022<\/a><\/p>\n\n\n\n<p>Let&#8217;s quickly go through this demo.<\/p>\n\n\n\n<p>First, restore the <a href=\"https:\/\/github.com\/Microsoft\/sql-server-samples\/releases\/download\/adventureworks\/AdventureWorks2016_EXT.bak\">AdventureWorks2016_EXT<\/a> database, clear the Query Store and set the compatibility level to 160 (2022);<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; gutter: false; title: ; notranslate\" title=\"\">\nUSE AdventureWorks2016_EXT;\nGO\nALTER DATABASE CURRENT SET COMPATIBILITY_LEVEL = 160;\nGO\nALTER DATABASE CURRENT SET QUERY_STORE CLEAR ALL;\nGO\nALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;\nGO\n<\/pre><\/div>\n\n\n<p>Create an index on the City column:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; gutter: false; title: ; notranslate\" title=\"\">\nCREATE NONCLUSTERED INDEX &#x5B;IX_Address_City] ON &#x5B;Person].&#x5B;Address](&#x5B;City] ASC);\n<\/pre><\/div>\n\n\n<p>Run the SELECT query below 16 times. At the time of writing this post, the CE feedback feature will trigger feedback at the sixteenth execution of a query. This number may change in the future, with a cumulative update or a newer version. <\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; gutter: false; highlight: [3]; title: ; notranslate\" title=\"\">\nSELECT AddressID, AddressLine1, AddressLine2\nFROM Person.Address\nWHERE StateProvinceID = 79 AND City = N&#039;Redmond&#039;;\nGO 16\n<\/pre><\/div>\n\n\n<p>For now the Execution plan looks like this:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"342\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_1_plan_nestedLoops-1024x342.jpg\" alt=\"\" class=\"wp-image-24459\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_1_plan_nestedLoops-1024x342.jpg 1024w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_1_plan_nestedLoops-300x100.jpg 300w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_1_plan_nestedLoops-768x256.jpg 768w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_1_plan_nestedLoops.jpg 1075w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p>Then, if we run the query one more time, the CE feedback is applied, at the seventeenth execution.<br>The execution plan now looks like that:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"505\" height=\"197\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_2_plan_scan.jpg\" alt=\"\" class=\"wp-image-24460\" style=\"width:395px;height:154px\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_2_plan_scan.jpg 505w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_2_plan_scan-300x117.jpg 300w\" sizes=\"auto, (max-width: 505px) 100vw, 505px\" \/><\/figure>\n<\/div>\n\n\n<p>There are details on what query hint is used inside the Query Store:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; gutter: false; title: ; notranslate\" title=\"\">\nSELECT * FROM sys.query_store_query_hints;\nSELECT * FROM sys.query_store_plan_feedback;\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1023\" height=\"156\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_3_QS_hints_feedback.jpg\" alt=\"\" class=\"wp-image-24461\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_3_QS_hints_feedback.jpg 1023w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_3_QS_hints_feedback-300x46.jpg 300w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_3_QS_hints_feedback-768x117.jpg 768w\" sizes=\"auto, (max-width: 1023px) 100vw, 1023px\" \/><\/figure>\n\n\n\n<p>So what happens here is that by using the latest Cardinality Estimation model (we are in compatibility level 160) the estimated number of rows for this query is not so good. We estimated 44 rows but processed 121 at runtime.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"471\" height=\"241\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_4_Focus_Wrong_estimate.jpg\" alt=\"\" class=\"wp-image-24462\" style=\"width:311px;height:159px\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_4_Focus_Wrong_estimate.jpg 471w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_4_Focus_Wrong_estimate-300x154.jpg 300w\" sizes=\"auto, (max-width: 471px) 100vw, 471px\" \/><\/figure>\n<\/div>\n\n\n<p>The CE Feedback feature applied the ASSUME_MIN_SELECTIVITY_FOR_FILTER_ESTIMATES query hint and we got a completely different execution plan with a better (perfect) estimation of the number of rows.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"589\" height=\"223\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_5_Focus_Wrong_estimate_2.jpg\" alt=\"\" class=\"wp-image-24463\" style=\"width:384px;height:145px\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_5_Focus_Wrong_estimate_2.jpg 589w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_5_Focus_Wrong_estimate_2-300x114.jpg 300w\" sizes=\"auto, (max-width: 589px) 100vw, 589px\" \/><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"h-explanations\">Explanations<\/h2>\n\n\n\n<p>Let&#8217;s try to understand why.<\/p>\n\n\n\n<p>The description of the hint, which can be found under the <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/t-sql\/queries\/hints-transact-sql-query?view=azuresqldb-current#use_hint\" target=\"_blank\" rel=\"noreferrer noopener\">USE HINT<\/a> documentation, helps us understand that it affects the way SQL Server assumes the level of correlation between AND predicates.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>ASSUME_MIN_SELECTIVITY_FOR_FILTER_ESTIMATES<\/p>\n\n\n\n<p>Causes SQL Server to generate a plan using minimum selectivity when estimating AND predicates for filters to account for <strong>full correlation<\/strong>.<\/p>\n<\/blockquote>\n\n\n\n<p>Additionally, there are two other related hints:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>ASSUME_FULL_INDEPENDENCE_FOR_FILTER_ESTIMATES<\/p>\n\n\n\n<p>Causes SQL Server to generate a plan using maximum selectivity when estimating AND predicates for filters to account for <strong>full independence<\/strong>. This hint name is the default behavior of the cardinality estimation model of SQL Server 2012 and earlier versions<\/p>\n<\/blockquote>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>ASSUME_PARTIAL_CORRELATION_FOR_FILTER_ESTIMATES<\/p>\n\n\n\n<p>Causes SQL Server to generate a plan using most to least selectivity when estimating AND predicates for filters to account for <strong>partial correlation<\/strong>. This hint name is the default behavior of the cardinality estimation model of SQL Server 2014 or higher.<\/p>\n<\/blockquote>\n\n\n\n<p>That is to say, they are 3 model assumptions to determine the selectivity of multiple predicates with an AND clause; full correlation, partial correlation, and full independence.<\/p>\n\n\n\n<p>This is well described in this white paper: <a href=\"https:\/\/learn.microsoft.com\/en-us\/previous-versions\/dn673537(v=msdn.10)?redirectedfrom=MSDN\">Optimizing Your Query Plans with the SQL Server 2014 Cardinality Estimator<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-full-independence\">Full independence<\/h3>\n\n\n\n<p>Under the model assumption of full independence, the selectivity of the individual predicates is multiplied together.<\/p>\n\n\n\n<p>Let&#8217;s find the selectivity of the predicates.<br>The selectivity is the estimated number of rows with a value equal to the predicate divided by the total number of rows in the table.<br>The selectivity can be derived from the statistics&#8217; histogram. This example uses values that are represented as RANGE_HI_KEY steps in the histograms, so it&#8217;s quite easy to get the selectivity.<\/p>\n\n\n\n<p>For the selectivity of the &#8220;Redmond&#8221; city, we look at the stats histogram of the city column index.<br>With the following query, we get a selectivity of <strong>0.006169063<\/strong>. 19614 is the number of rows in the Address table.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; gutter: false; title: ; notranslate\" title=\"\">\nSELECT \n\th.step_number\n\t, h.range_high_key\n\t, h.range_rows\n\t, h.equal_rows\n\t, h.average_range_rows\n\t, h.equal_rows\/19614 AS predicate_selectivity\nFROM sys.stats AS s\n\tCROSS APPLY sys.dm_db_stats_histogram(s.&#x5B;object_id], s.stats_id) AS h\nWHERE s.&#x5B;name] = &#039;IX_Address_City&#039;\n  AND range_high_key = &#039;Redmond&#039;\n<\/pre><\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"758\" height=\"62\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_6_Redmond_Selectivity.jpg\" alt=\"\" class=\"wp-image-24466\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_6_Redmond_Selectivity.jpg 758w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_6_Redmond_Selectivity-300x25.jpg 300w\" sizes=\"auto, (max-width: 758px) 100vw, 758px\" \/><\/figure>\n<\/div>\n\n\n<p>The Washington state (ID = 79) gets a selectivity of <strong>0.1343938<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"763\" height=\"62\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_7_State_Selectivity.jpg\" alt=\"\" class=\"wp-image-24467\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_7_State_Selectivity.jpg 763w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_7_State_Selectivity-300x24.jpg 300w\" sizes=\"auto, (max-width: 763px) 100vw, 763px\" \/><\/figure>\n<\/div>\n\n\n<p>The number of rows estimated for the whole predicate under the Independence model assumption is 16.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; gutter: false; title: ; notranslate\" title=\"\">\nSELECT 0.006169063 * 0.1343938 * 19614 -- 16.26165\n<\/pre><\/div>\n\n\n<p>We can verify this by using the query hint associated with the full independence model assumption:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; gutter: false; title: ; notranslate\" title=\"\">\nSELECT AddressID, AddressLine1, AddressLine2\nFROM Person.Address\nWHERE StateProvinceID = 79 AND City = N&#039;Redmond&#039;\nOPTION(USE HINT(&#039;ASSUME_FULL_INDEPENDENCE_FOR_FILTER_ESTIMATES&#039;), RECOMPILE) \n<\/pre><\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"602\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence-1024x602.jpg\" alt=\"\" class=\"wp-image-24469\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence-1024x602.jpg 1024w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence-300x176.jpg 300w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence-768x451.jpg 768w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence.jpg 1048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p>We get the exact number we just calculated of 16.2616 estimated rows.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-partial-correlation\">Partial correlation<\/h3>\n\n\n\n<p>To assume some correlation, SQL Server uses the Partial correlation model which is based on an exponential backoff.<br>The predicates are sorted in ascending order of selectivity. SQL Server then &#8220;moderates\u201d each successive predicate by taking larger square roots.<br>Let&#8217;s say we have 3 predicates; P1 to P3 sorted by selectivity, the row estimate formula would be:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; gutter: false; title: ; notranslate\" title=\"\">\nSELECT P1 * SQRT(P2) * SQRT(SQRT(P3)) * TableRowCount\n<\/pre><\/div>\n\n\n<p>In our case, we get:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; gutter: false; title: ; notranslate\" title=\"\">\nSELECT 0.006169063 * SQRT(0.1343938) * 19614 -- 44.3583\n<\/pre><\/div>\n\n\n<p>This is what we got before the CE feedback was triggered; it&#8217;s the default behavior since SQL Server 2014.<br><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"471\" height=\"241\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_4_Focus_Wrong_estimate.jpg\" alt=\"\" class=\"wp-image-24462\" style=\"width:311px;height:159px\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_4_Focus_Wrong_estimate.jpg 471w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_4_Focus_Wrong_estimate-300x154.jpg 300w\" sizes=\"auto, (max-width: 471px) 100vw, 471px\" \/><\/figure>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-full-correlation\">Full correlation<\/h3>\n\n\n\n<p>Under full correlation, SQL Server just takes the most selective predicate for the whole conjunction of predicates.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; gutter: false; title: ; notranslate\" title=\"\">\nSELECT 0.006169063 * 19614 -- 121.00\n<\/pre><\/div>\n\n\n<p>We get 121 rows for Redmond as seen in the histogram earlier.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-ce-feedback-behavior\">CE Feedback behavior<\/h3>\n\n\n\n<p>For this specific query, the CE Feedback feature did not just try to use the &#8220;legacy CE model&#8221; with the full independence assumption, it found that there is a strong correlation between both predicates and applied the full correlation assumption. This is very nice.<\/p>\n\n\n\n<p>CE Feedback will look at the row estimates and tries to adjust. If the number of rows is overestimated it means that the predicates are more independent. If the estimation is too low there is more correlation than expected.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-conclusion\">Conclusion<\/h2>\n\n\n\n<p>The following table summarizes the assumption models, hints, and the number of estimated rows for this query example.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"99\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_9_Tableau_conclusion-1024x99.jpg\" alt=\"\" class=\"wp-image-24473\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_9_Tableau_conclusion-1024x99.jpg 1024w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_9_Tableau_conclusion-300x29.jpg 300w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_9_Tableau_conclusion-768x74.jpg 768w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_9_Tableau_conclusion.jpg 1497w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>I hope that this blog will help you understand a little bit more about how the Query Optimizer is working and what CE Feedback is doing in SQL Server 2022.<br>Remember that CE Feedback is not limited to this predicate correlation scenario, it will also affect &#8220;Join Containment&#8221;, and &#8220;Row Goal&#8221;.<\/p>\n\n\n\n<p>In addition to all the links provided above I would also recommend reading Paul White&#8217;s answer to this StackExchange question: <a href=\"https:\/\/dba.stackexchange.com\/questions\/20597\/how-does-sql-server-know-predicates-are-correlated\" target=\"_blank\" rel=\"noreferrer noopener\">How does SQL Server know predicates are correlated?<\/a><\/p>\n\n\n\n<p>Written by <a href=\"https:\/\/www.linkedin.com\/in\/steven-naudet-aa540158\/\">Steven Naudet<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>SQL Server 2022 introduced &#8220;CE Feedback&#8220;, a feature that adjusts some Cardinality Estimation model assumptions at a query level by applying Query Store hints. In this blog post, I&#8217;ll use an example query from the CE Feedback documentation to look in more detail at how CE works. The goal is to better understand how SQL [&hellip;]<\/p>\n","protected":false},"author":26,"featured_media":24469,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[99],"tags":[2911,2912,2913,51],"type_dbi":[],"class_list":["post-24265","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sql-server","tag-cardinality-estimation","tag-ce-feedback","tag-correlation","tag-sql-server"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.2) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>SQL Server: How Correlation assumptions work for multiple predicates - dbi Blog<\/title>\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.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"SQL Server: How Correlation assumptions work for multiple predicates\" \/>\n<meta property=\"og:description\" content=\"SQL Server 2022 introduced &#8220;CE Feedback&#8220;, a feature that adjusts some Cardinality Estimation model assumptions at a query level by applying Query Store hints. In this blog post, I&#8217;ll use an example query from the CE Feedback documentation to look in more detail at how CE works. The goal is to better understand how SQL [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2023-04-10T05:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-10-01T10:10:55+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1048\" \/>\n\t<meta property=\"og:image:height\" content=\"616\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Microsoft Team\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Microsoft Team\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/\"},\"author\":{\"name\":\"Microsoft Team\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/bfab48333280d616e1170e7369df90a4\"},\"headline\":\"SQL Server: How Correlation assumptions work for multiple predicates\",\"datePublished\":\"2023-04-10T05:00:00+00:00\",\"dateModified\":\"2025-10-01T10:10:55+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/\"},\"wordCount\":1061,\"commentCount\":0,\"image\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence.jpg\",\"keywords\":[\"Cardinality Estimation\",\"CE Feedback\",\"Correlation\",\"SQL Server\"],\"articleSection\":[\"SQL Server\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/\",\"name\":\"SQL Server: How Correlation assumptions work for multiple predicates - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence.jpg\",\"datePublished\":\"2023-04-10T05:00:00+00:00\",\"dateModified\":\"2025-10-01T10:10:55+00:00\",\"author\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/bfab48333280d616e1170e7369df90a4\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#primaryimage\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence.jpg\",\"contentUrl\":\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence.jpg\",\"width\":1048,\"height\":616},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\/\/www.dbi-services.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"SQL Server: How Correlation assumptions work for multiple predicates\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/bfab48333280d616e1170e7369df90a4\",\"name\":\"Microsoft Team\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/c44a1a792c059f24055763aa77d80a244467f6eef724a8bd13db8d4a350b7a4c?s=96&d=mm&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/c44a1a792c059f24055763aa77d80a244467f6eef724a8bd13db8d4a350b7a4c?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/c44a1a792c059f24055763aa77d80a244467f6eef724a8bd13db8d4a350b7a4c?s=96&d=mm&r=g\",\"caption\":\"Microsoft Team\"},\"url\":\"https:\/\/www.dbi-services.com\/blog\/author\/microsoft-team\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"SQL Server: How Correlation assumptions work for multiple predicates - dbi Blog","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.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/","og_locale":"en_US","og_type":"article","og_title":"SQL Server: How Correlation assumptions work for multiple predicates","og_description":"SQL Server 2022 introduced &#8220;CE Feedback&#8220;, a feature that adjusts some Cardinality Estimation model assumptions at a query level by applying Query Store hints. In this blog post, I&#8217;ll use an example query from the CE Feedback documentation to look in more detail at how CE works. The goal is to better understand how SQL [&hellip;]","og_url":"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/","og_site_name":"dbi Blog","article_published_time":"2023-04-10T05:00:00+00:00","article_modified_time":"2025-10-01T10:10:55+00:00","og_image":[{"width":1048,"height":616,"url":"http:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence.jpg","type":"image\/jpeg"}],"author":"Microsoft Team","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Microsoft Team","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/"},"author":{"name":"Microsoft Team","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/bfab48333280d616e1170e7369df90a4"},"headline":"SQL Server: How Correlation assumptions work for multiple predicates","datePublished":"2023-04-10T05:00:00+00:00","dateModified":"2025-10-01T10:10:55+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/"},"wordCount":1061,"commentCount":0,"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence.jpg","keywords":["Cardinality Estimation","CE Feedback","Correlation","SQL Server"],"articleSection":["SQL Server"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/","url":"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/","name":"SQL Server: How Correlation assumptions work for multiple predicates - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#primaryimage"},"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence.jpg","datePublished":"2023-04-10T05:00:00+00:00","dateModified":"2025-10-01T10:10:55+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/bfab48333280d616e1170e7369df90a4"},"breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#primaryimage","url":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence.jpg","contentUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2023\/04\/Blog35_8_EP_Full_independence.jpg","width":1048,"height":616},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/sql-server-how-correlation-assumptions-work-for-multiple-predicates\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"SQL Server: How Correlation assumptions work for multiple predicates"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/bfab48333280d616e1170e7369df90a4","name":"Microsoft Team","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/c44a1a792c059f24055763aa77d80a244467f6eef724a8bd13db8d4a350b7a4c?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/c44a1a792c059f24055763aa77d80a244467f6eef724a8bd13db8d4a350b7a4c?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/c44a1a792c059f24055763aa77d80a244467f6eef724a8bd13db8d4a350b7a4c?s=96&d=mm&r=g","caption":"Microsoft Team"},"url":"https:\/\/www.dbi-services.com\/blog\/author\/microsoft-team\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/24265","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/26"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=24265"}],"version-history":[{"count":45,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/24265\/revisions"}],"predecessor-version":[{"id":40625,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/24265\/revisions\/40625"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media\/24469"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=24265"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=24265"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=24265"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=24265"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}