Memory Grant Analysis with AI

Memory grants are one of those things that only become visible when they’re already a problem. A query requests 4 GB of workspace memory for a sort or hash join, gets it, uses 12 MB, and holds the rest hostage for the duration of execution. Meanwhile, other queries queue behind RESOURCE_SEMAPHORE waits because there’s no workspace memory left. Or the opposite: a query gets a tiny grant, runs out of memory mid-execution, and spills to tempdb — turning a 2-second query into a 45-second one.

The data to diagnose both scenarios lives in sys.dm_exec_query_memory_grants and sys.dm_exec_query_stats. The challenge is interpreting it under pressure and knowing which fix applies to which pattern. This is where an AI agent earns its keep.

Collecting Memory Grant Data

Start with currently executing queries and their memory grants:

For queries waiting for grants (the RESOURCE_SEMAPHORE case), check for rows where granted_memory_kb is NULL:

For historical analysis of spills, Query Store is your best source in SQL Server 2022 and later — it tracks last_tempdb_space_used at the plan level. For earlier versions, check sys.dm_exec_query_stats columns like total_spills (added in SQL Server 2017).

Feeding the Data to the Agent

Here’s the prompt pattern I use. Include actual numbers — the agent can’t diagnose “high memory grants” without seeing the data.

What the Agent Produces

The agent identifies three distinct patterns in this data:

Session 112: Massive over-grant. Requested and received 4 GB but only used 14 MB — a 300:1 ratio. This is almost certainly a cardinality estimation error. The optimizer estimated a huge sort or hash operation and reserved memory for it, but the actual data volume was tiny. This query is holding 4 GB of workspace memory hostage while sessions 215 and 301 wait.

Session 198: Healthy grant. Requested 2 GB, used 1.8 GB. This is a legitimate large operation — the grant matches usage. No action needed on this one, though you might ask whether the query needs to process that much data.

Sessions 215 and 301: Grant waiters. Both are waiting for memory grants (granted_kb is NULL). They need 512 MB and 256 MB respectively — not unreasonable amounts — but they can’t get memory because session 112 is holding 4 GB it isn’t using. This is the direct cause of the RESOURCE_SEMAPHORE waits.

Session 87: Spill candidate. Granted exactly what it’s using (128 MB). Check the execution plan for sort or hash spill warnings — if the query originally needed more than 128 MB but was capped, it may be spilling to tempdb.

What I Validated and Changed

I pulled the execution plan for session 112 and confirmed the agent’s suspicion: a sort operator estimated 2.8 million rows but only processed 1,200. The cardinality estimate was off because statistics on the filtered column were stale — last updated 3 weeks ago when the table had very different data distribution.

After the statistics update, I forced a recompile of the procedure. The new plan requested 18 MB instead of 4 GB.

For the longer-term fix, I added memory grant feedback guardrails. SQL Server 2022 has memory grant feedback persistence (part of Intelligent Query Processing) that learns from execution history and adjusts grants automatically. But for critical queries where I can’t wait for the feedback loop, I use query hints:

MAX_GRANT_PERCENT caps the grant at a percentage of total workspace memory. At 5% of 32 GB, that’s ~1.6 GB — still generous, but prevents the 4 GB runaway scenario. I also use MIN_GRANT_PERCENT for queries that consistently spill:

For broader protection, consider Resource Governor to cap memory grants per workload group — especially useful for separating ad-hoc reporting queries from OLTP workloads:

The Diagnostic Checklist

When the agent flags a memory grant problem, here’s the validation sequence:

  1. Over-grants (granted >> used): Check statistics freshness and cardinality estimates. Update statistics, then recompile.
  2. Spills (used = granted and plan shows spill warnings): The query needs more memory. Check if MIN_GRANT_PERCENT or updated statistics would help.
  3. RESOURCE_SEMAPHORE waits: Find the sessions holding the most granted memory. Usually one or two over-granted queries are starving everything else.
  4. Persistent issues: Enable memory grant feedback (on by default in SQL Server 2022 with Query Store enabled) or use Resource Governor.

Try This Yourself

  1. Run the active memory grants query above during your peak workload.
  2. Look for sessions with a high granted-to-used ratio — anything above 5:1 is worth investigating.
  3. Feed the output to your AI agent with your server’s memory configuration.
  4. Check statistics freshness on the tables involved in over-granted queries.
  5. For chronic over-granters, test MAX_GRANT_PERCENT in a non-production environment first — setting it too low will cause spills.

Memory grants are a balancing act. The agent helps you spot the imbalance faster, but the fix depends on whether the root cause is stale statistics, bad cardinality estimates, or genuinely large data operations that need Resource Governor limits.

For more on AI-assisted performance diagnostics, see Post 8: Wait Stats, Deadlocks, and Blocking Chains. For building automated monitoring that catches these patterns before they become incidents, see Post 13: Building Custom Monitoring.


Part of the ALTER DBA ADD AGENT series.