Check SQL Server Cardinality Estimation Issues in 45 Seconds. The "45 Seconds DBA Series". Part 12
Before we dive into today's topic, if you missed my previous post you can take a look at Check Execution Plans in 45 Seconds.
👉 If you found this deep-dive helpful, feel free to check out the ads—your support helps me keep creating high-quality SQL Server content for the community.
Check SQL Server Cardinality Estimation Issues in 45 Seconds
Execution Engine Deep Dive | Part 12
In this post, I will show you how to identify the silent killer of performance: the "Estimate vs Actual" row gap. Mastering Cardinality Estimation is the difference between a sub-second response and a server-wide timeout.
🧠 TL;DR BOX
✔️ Cardinality Estimation (CE) is the Optimizer's prediction of how many rows a query will process.
✔️ A massive discrepancy between Estimated and Actual rows leads to sub-optimal join choices and memory grant spills.
✔️ Primary culprits: Outdated statistics, table variables, and complex non-SARGable predicates.
✔️ Diagnosis takes less than 45 seconds using the plan cache or Execution Plan comparison.
Hi SQL SERVER Guys and Gals,
We all know how important it is to make every second count when managing SQL Server environments. When the Query Optimizer makes a decision, it relies on a "guess" called Cardinality Estimation. If that guess is wrong, the entire execution plan is built on a lie. Let's dive into how you can spot these lies instantly.
🔍 DIAGNOSIS: The Cardinality Skew
🧠 What it really is: Cardinality Estimation is the mathematical model SQL Server uses to predict the number of rows returned by each operator. The Optimizer uses Statistics (histograms) to make these calls. If the stats are stale or the query is too complex (e.g., multiple joins with skewed data), the CE fails.
💣 The Problem: When SQL Server expects 1 row but gets 1,000,000:
- It chooses a Nested Loop Join instead of a Hash Join.
- It requests a tiny Memory Grant, causing a massive spill to TempDB.
- CPU usage spikes as the engine struggles with an inefficient plan.
🧪 QUERY: Identify Skewed Plans in Cache
Use this script to find the top 20 queries where the Optimizer's "guess" was significantly different from reality.
-- 🔍 CE Skew Diagnostic Query
SELECT TOP 20
st.text AS [Query Text],
qp.query_plan AS [Plan],
qs.total_worker_time / qs.execution_count AS [Avg CPU],
CAST(qs.max_rows AS FLOAT) / NULLIF(qs.max_grant_kb,0) AS [Row Density],
stat.last_execution_time,
-- Comparing Max Rows vs Average Rows to find variance
qs.max_rows,
qs.min_rows,
qs.total_rows / qs.execution_count AS [Avg Rows]
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
ORDER BY [Avg Rows] DESC;
🚀 FIX: Closing the Gap
If you identify a CE issue, you have three immediate paths to resolution:
- ✔️ Update Statistics: Run
UPDATE STATISTICS [TableName] WITH FULLSCAN;. Often, a 10% sample isn't enough for skewed data. - ✔️ Replace Table Variables: Table variables don't have statistics (mostly). Use #TempTables so the Optimizer can see the data distribution before choosing the plan.
- ✔️ Query Hints: In SQL 2014+, you can use
OPTION (USE HINT('FORCE_LEGACY_CARDINALITY_ESTIMATION'))if the new model is producing regressions on legacy code.
🚀 My REAL Strategy
In my 25 years of experience, the biggest mistake DBAs make is blaming the code when the problem is the Metadata. If you see a plan where a Hash Match operator is spilling to disk, don't just add an index. Check the CE. If the estimate was 100 rows and it processed 10 million, no index in the world will fix that memory grant deficit. Fix the stats first, then look at the T-SQL.
📊 TAKEAWAY
Cardinality estimation is the heart of the Execution Engine. Always compare Estimated vs. Actual. If they are off by more than 10x, you aren't tuning a query; you're fighting a broken model. Correct the model, and the performance will follow.
📢 Support the Blog: Did you find this deep-dive helpful? The ads you see here are selected to reflect your interests. If a partner's offer catches your eye, give it a look! Your engagement helps me continue publishing premium SQL Server content for the community.
Comments
Post a Comment