<?xml version="1.0" encoding="UTF-8" standalone="no"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" version="2.0">

<channel>
	<title>MarlonRibunal.com</title>
	<atom:link href="https://marlonribunal.com/feed/?max-results=10" rel="self" type="application/rss+xml"/>
	<link>https://marlonribunal.com</link>
	<description>SQL, Code, Coffee, etc.</description>
	<lastBuildDate>Sat, 26 Sep 2026 08:19:56 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.2</generator>
	<xhtml:meta content="noindex" name="robots" xmlns:xhtml="http://www.w3.org/1999/xhtml"/><item>
		<title>Creating a Custom SQL Server Security Checklist Using the DoD STIG</title>
		<link>https://marlonribunal.com/creating-a-custom-sql-server-security-checklist-using-the-dod-stig/</link>
					<comments>https://marlonribunal.com/creating-a-custom-sql-server-security-checklist-using-the-dod-stig/#respond</comments>
		
		<dc:creator><![CDATA[Marlon Ribunal]]></dc:creator>
		<pubDate>Tue, 22 Sep 2026 11:30:00 +0000</pubDate>
				<category><![CDATA[SQL Server]]></category>
		<guid isPermaLink="false">https://marlonribunal.com/?p=2973</guid>

					<description><![CDATA[<p>The STIG is detailed, which is a good thing, but I found myself wanting something a little more practical for day-to-day DBA work. Something I could open, work through one item at a time, record what I found, and come back to later without having to navigate through the entire STIG document every time.</p>
<p>That led me to the idea of creating my own SQL Server security checklist. <a href="https://marlonribunal.com/creating-a-custom-sql-server-security-checklist-using-the-dod-stig/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://marlonribunal.com/creating-a-custom-sql-server-security-checklist-using-the-dod-stig/">Creating a Custom SQL Server Security Checklist Using the DoD STIG</a> first appeared on <a href="https://marlonribunal.com">SQL, Code, Coffee, Etc.</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">Here&#8217;s a follow up for our US Department of Defense STIG document. In my previous post, <a href="https://marlonribunal.com/sql-server-security-hardening-guide-using-the-dod-stig-checklist/" title="">SQL Server Security Hardening Guide Using the DoD STIG Checklist</a>, I walked through how I used the DoD STIG checklist as a starting point for reviewing and hardening a SQL Server environment.</p>



<p class="wp-block-paragraph">After going through the checklist, I started thinking about what I would actually want to use the next time I perform a security review.</p>



<p class="wp-block-paragraph">The DoD STIG for SQL Server is a great, solid starting point for establishing your security practices with SQL Server. In fact, it&#8217;s also a good template for your own STIG in your organization. So, you may want to create a custom checklist that makes sense from the perspective of your SQL Server environment.</p>



<p class="wp-block-paragraph">The STIG is detailed, which is a good thing, but I found myself wanting something a little more practical for day-to-day DBA work. Something I could open, work through one item at a time, record what I found, and come back to later without having to navigate through the entire STIG document every time.</p>



<h2 class="wp-block-heading">Questions to Ask</h2>



<p class="wp-block-paragraph">I want it to answer some simple questions:</p>



<ul class="wp-block-list">
<li>What am I checking?</li>



<li>Why am I checking it?</li>



<li>How can I verify it?</li>



<li>What does PASS or FAIL look like?</li>



<li>What evidence should I record?</li>



<li>Does this requirement actually apply to this environment?</li>



<li>If I can&#8217;t meet a requirement, how do I document the exception?</li>
</ul>



<p class="wp-block-paragraph">So in this post, I&#8217;ll walk through how I&#8217;m building the checklist, based on the DoD STIG as the baseline (and I can then organize it into something I can actually use as a DBA).</p>



<p class="wp-block-paragraph">The main thing here is to <strong>understand what the STIG is asking you to verify</strong>.</p>



<p class="wp-block-paragraph">Once I have the STIG requirements in front of me, the next step is to break each rule down into information that I can actually work with. Rather than simply copying the requirement into my checklist, I want to capture a few key details for each rule. </p>



<p class="wp-block-paragraph">This gives me enough information to understand what I&#8217;m checking, how I can validate it, and what I should record when I&#8217;m done.</p>



<p class="wp-block-paragraph">Again, this STIG is just a starting point. Capture the checklist in a separate document that you can share in your organization.</p>



<h2 class="wp-block-heading">What to Capture?</h2>



<p class="wp-block-paragraph">For every rule, capture:</p>



<ul class="wp-block-list">
<li>STIG ID</li>



<li>Severity</li>



<li>Requirement</li>



<li>Check</li>



<li>Fix</li>



<li>Instance or Database</li>



<li>Applicable?</li>



<li>Current status</li>
</ul>



<h2 class="wp-block-heading">Let&#8217;s Create a Checklist</h2>



<p class="wp-block-paragraph">Let&#8217;s open the STIG Viewer, at the <strong>Checklist </strong>section, click New to create a new checklist.</p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="747" src="https://marlonribunal.com/wp-content/uploads/2026/09/image-1024x747.png" alt="" class="wp-image-2974" srcset="https://marlonribunal.com/wp-content/uploads/2026/09/image-1024x747.png 1024w, https://marlonribunal.com/wp-content/uploads/2026/09/image-300x219.png 300w, https://marlonribunal.com/wp-content/uploads/2026/09/image-767x560.png 767w, https://marlonribunal.com/wp-content/uploads/2026/09/image-1536x1121.png 1536w, https://marlonribunal.com/wp-content/uploads/2026/09/image-2048x1495.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Let&#8217;s select to create a checklist for a SQL Server Instance.</p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="720" src="https://marlonribunal.com/wp-content/uploads/2026/09/image-1-1024x720.png" alt="" class="wp-image-2975" srcset="https://marlonribunal.com/wp-content/uploads/2026/09/image-1-1024x720.png 1024w, https://marlonribunal.com/wp-content/uploads/2026/09/image-1-300x211.png 300w, https://marlonribunal.com/wp-content/uploads/2026/09/image-1-767x539.png 767w, https://marlonribunal.com/wp-content/uploads/2026/09/image-1-1536x1079.png 1536w, https://marlonribunal.com/wp-content/uploads/2026/09/image-1-2048x1439.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">You have to options: Add individual rules or add all the rules in the STIG. Click the search icon to pick the individual rules or the plus sign to add all the rules. For the purpose of this blog post, let&#8217;s add few rules.</p>



<p class="wp-block-paragraph">Select the rule by clicking the <strong>Plus</strong> sign. Select all that you want added in your checklist.</p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="723" src="https://marlonribunal.com/wp-content/uploads/2026/09/image-2-1024x723.png" alt="" class="wp-image-2976" srcset="https://marlonribunal.com/wp-content/uploads/2026/09/image-2-1024x723.png 1024w, https://marlonribunal.com/wp-content/uploads/2026/09/image-2-300x212.png 300w, https://marlonribunal.com/wp-content/uploads/2026/09/image-2-768x542.png 768w, https://marlonribunal.com/wp-content/uploads/2026/09/image-2-1536x1084.png 1536w, https://marlonribunal.com/wp-content/uploads/2026/09/image-2-2048x1445.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">To save the checklist, navigate to the burger menu in the top left-hand corner and select <strong>Save</strong>. Give the checklist file an intuitive name.</p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="719" src="https://marlonribunal.com/wp-content/uploads/2026/09/image-3-1024x719.png" alt="" class="wp-image-2977" srcset="https://marlonribunal.com/wp-content/uploads/2026/09/image-3-1024x719.png 1024w, https://marlonribunal.com/wp-content/uploads/2026/09/image-3-300x211.png 300w, https://marlonribunal.com/wp-content/uploads/2026/09/image-3-767x538.png 767w, https://marlonribunal.com/wp-content/uploads/2026/09/image-3-1536x1078.png 1536w, https://marlonribunal.com/wp-content/uploads/2026/09/image-3-2048x1437.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Once saved, you can close the checklist builder. The STIG Checklist options will then give you a couple of options to load or create another checklist. Let&#8217;s open the checklist that we just created.</p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="721" src="https://marlonribunal.com/wp-content/uploads/2026/09/image-4-1024x721.png" alt="" class="wp-image-2978" srcset="https://marlonribunal.com/wp-content/uploads/2026/09/image-4-1024x721.png 1024w, https://marlonribunal.com/wp-content/uploads/2026/09/image-4-300x211.png 300w, https://marlonribunal.com/wp-content/uploads/2026/09/image-4-767x540.png 767w, https://marlonribunal.com/wp-content/uploads/2026/09/image-4-1536x1081.png 1536w, https://marlonribunal.com/wp-content/uploads/2026/09/image-4-2048x1441.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Review the checklist and check it against a specific instance or database that you want to assess. Here you can note the instance/database information and mark each rule with three statuses: </p>



<p class="wp-block-paragraph">Green Check Icon: <strong>Not a Finding</strong> (meaning instance/database pass the rule), </p>



<p class="wp-block-paragraph">Red Exclamation: <strong>Open</strong> (for further review), or </p>



<p class="wp-block-paragraph">Crossed Circle: <strong>Not Applicable</strong></p>



<p class="wp-block-paragraph">Default Grey Circle: <strong>Not reviewed</strong></p>



<p class="wp-block-paragraph">Keep clicking the gray button to cycle through the statuses.</p>



<p class="wp-block-paragraph">You can also leave a comment and findings details in each of the rules in the designated boxes at the bottom.</p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="716" src="https://marlonribunal.com/wp-content/uploads/2026/09/image-5-1024x716.png" alt="" class="wp-image-2979" srcset="https://marlonribunal.com/wp-content/uploads/2026/09/image-5-1024x716.png 1024w, https://marlonribunal.com/wp-content/uploads/2026/09/image-5-300x210.png 300w, https://marlonribunal.com/wp-content/uploads/2026/09/image-5-768x537.png 768w, https://marlonribunal.com/wp-content/uploads/2026/09/image-5-1536x1074.png 1536w, https://marlonribunal.com/wp-content/uploads/2026/09/image-5-2048x1432.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">You can then export the checklist if you want to keep a separate file for the assessment (html and then print it to a pdf file).</p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="716" src="https://marlonribunal.com/wp-content/uploads/2026/09/image-6-1024x716.png" alt="" class="wp-image-2980" srcset="https://marlonribunal.com/wp-content/uploads/2026/09/image-6-1024x716.png 1024w, https://marlonribunal.com/wp-content/uploads/2026/09/image-6-300x210.png 300w, https://marlonribunal.com/wp-content/uploads/2026/09/image-6-768x537.png 768w, https://marlonribunal.com/wp-content/uploads/2026/09/image-6-1536x1074.png 1536w, https://marlonribunal.com/wp-content/uploads/2026/09/image-6-2048x1432.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Here&#8217;s some screenshots of the  the example html&#8230;</p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="751" src="https://marlonribunal.com/wp-content/uploads/2026/09/image-7-1024x751.png" alt="" class="wp-image-2981" srcset="https://marlonribunal.com/wp-content/uploads/2026/09/image-7-1024x751.png 1024w, https://marlonribunal.com/wp-content/uploads/2026/09/image-7-300x220.png 300w, https://marlonribunal.com/wp-content/uploads/2026/09/image-7-767x562.png 767w, https://marlonribunal.com/wp-content/uploads/2026/09/image-7-1536x1126.png 1536w, https://marlonribunal.com/wp-content/uploads/2026/09/image-7-2048x1501-1.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="746" src="https://marlonribunal.com/wp-content/uploads/2026/09/image-8-1024x746.png" alt="" class="wp-image-2982" srcset="https://marlonribunal.com/wp-content/uploads/2026/09/image-8-1024x746.png 1024w, https://marlonribunal.com/wp-content/uploads/2026/09/image-8-300x219.png 300w, https://marlonribunal.com/wp-content/uploads/2026/09/image-8-767x559.png 767w, https://marlonribunal.com/wp-content/uploads/2026/09/image-8-1536x1119.png 1536w, https://marlonribunal.com/wp-content/uploads/2026/09/image-8-2048x1493.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading">Your Checklist as Your Tool</h2>



<p class="wp-block-paragraph">Instead of reproducing the STIG&#8217;s structure, I&#8217;d create something a DBA can work through. I&#8217;d create a checklist for the following categories:</p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Category</th><th>What you&#8217;re checking</th></tr></thead><tbody><tr><td>Authentication</td><td>How users authenticate</td></tr><tr><td>Authorization</td><td>Who has access to what</td></tr><tr><td>Accounts &amp; Logins</td><td>SQL logins, Windows accounts, disabled accounts</td></tr><tr><td>Privileges</td><td><code>sysadmin</code>, server roles, database roles</td></tr><tr><td>Auditing</td><td>Login and security-related auditing</td></tr><tr><td>Encryption</td><td>TDE, TLS, encryption at rest</td></tr><tr><td>Network Security</td><td>SQL ports, protocols, exposure</td></tr><tr><td>Configuration</td><td>SQL Server security-related configuration</td></tr><tr><td>Database Security</td><td>Database-level permissions and ownership</td></tr><tr><td>Service Accounts</td><td>SQL Server service identities</td></tr><tr><td>Agent Security</td><td>SQL Agent jobs, proxies, credentials</td></tr><tr><td>Sensitive Data</td><td>PII and other protected information</td></tr><tr><td>Monitoring</td><td>Security events and changes</td></tr><tr><td>Documentation</td><td>Exceptions, evidence and remediation</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">That and among other things that may be applicable to whichever environment I happen to be working on.</p>



<p class="wp-block-paragraph">This is where your checklist becomes <strong>your own tool</strong>, rather than just another copy of the STIG.</p>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading">Most Important Thing, Document</h2>



<p class="wp-block-paragraph">This is an important part of the checklist. I don&#8217;t want the process to be simply about finding a problem and <strong>immediately changing the configuration</strong>. Involve everyone and, needless to say, document.</p>



<p class="wp-block-paragraph">The goal is to first understand the current state, evaluate whether the setting actually needs to be changed, make the appropriate remediation if necessary, and then validate the change. This gives me a more deliberate process instead of treating every finding as something that automatically requires a configuration change.</p>



<p class="wp-block-paragraph">This process would look as simple as the following:</p>



<p class="wp-block-paragraph"><strong>1. Check</strong> &#8211; Determine the current state.</p>



<p class="wp-block-paragraph"><strong>2. Evaluate</strong> &#8211; Decide whether the configuration is appropriate for your environment.</p>



<p class="wp-block-paragraph"><strong>3. Remediate</strong> &#8211; Make the change if necessary.</p>



<p class="wp-block-paragraph"><strong>4. Validate</strong> &#8211; Run the check again.</p>



<p class="wp-block-paragraph"><strong>5. Document</strong> &#8211; Record what changed.</p>



<p class="wp-block-paragraph">That gives you a repeatable process:</p>



<pre class="wp-block-preformatted"> <code>      CHECK
         ↓
      EVALUATE
         ↓
     REMEDIATE
         ↓
      VALIDATE
         ↓
     DOCUMENT</code></pre>



<p class="wp-block-paragraph">And I&#8217;d emphasize that <strong>STIG compliance doesn&#8217;t automatically mean every setting should simply be changed without considering the environment</strong>.</p>



<p class="wp-block-paragraph">If this was a real checklist for a SQL Server environment I am responsible for, this is my starting point. I expect the checklist to change as I use it, find gaps, and learn more about what works in an actual SQL Server environment. </p>



<p class="wp-block-paragraph">The STIG gives me a solid baseline, but turning those requirements into something I can consistently use as a DBA makes the exercise much more useful for me. </p>



<p class="wp-block-paragraph">My next step is to take these checks and start turning them into T-SQL scripts where possible, so instead of manually checking everything, I can let SQL Server help me identify what needs attention.</p>



<p class="wp-block-paragraph">Have fun and enjoy securing your SQL Server!</p><p>The post <a href="https://marlonribunal.com/creating-a-custom-sql-server-security-checklist-using-the-dod-stig/">Creating a Custom SQL Server Security Checklist Using the DoD STIG</a> first appeared on <a href="https://marlonribunal.com">SQL, Code, Coffee, Etc.</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://marlonribunal.com/creating-a-custom-sql-server-security-checklist-using-the-dod-stig/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>T-SQL Tuesday #202 SQL Server Outage You’ll Never Forget: A Roundup</title>
		<link>https://marlonribunal.com/t-sql-tuesday-202-sql-server-outage-youll-never-forget-a-roundup/</link>
					<comments>https://marlonribunal.com/t-sql-tuesday-202-sql-server-outage-youll-never-forget-a-roundup/#comments</comments>
		
		<dc:creator><![CDATA[Marlon Ribunal]]></dc:creator>
		<pubDate>Tue, 15 Sep 2026 07:10:00 +0000</pubDate>
				<category><![CDATA[SQL Server]]></category>
		<guid isPermaLink="false">https://marlonribunal.com/?p=2960</guid>

					<description><![CDATA[<p>When I put together the invitation for T-SQL Tuesday #202, I wasn't sure what kind of stories would come out of it.</p>
<p>The topic was simple:</p>
<p>That one SQL Server outage you'll never forget.</p>
<p>I expected stories about bad queries, failed deployments, storage problems, or maybe a database that decided to have a very bad day. What I got was much more interesting. <a href="https://marlonribunal.com/t-sql-tuesday-202-sql-server-outage-youll-never-forget-a-roundup/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://marlonribunal.com/t-sql-tuesday-202-sql-server-outage-youll-never-forget-a-roundup/">T-SQL Tuesday #202 SQL Server Outage You’ll Never Forget: A Roundup</a> first appeared on <a href="https://marlonribunal.com">SQL, Code, Coffee, Etc.</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph"><strong><em>Update: I initially missed to include Edwin Sarmiento, Andy Levy, Chad Callihan, and Rebecca Lewis outage stories. I just added them in the roundup below.</em></strong></p>



<p class="wp-block-paragraph">When I put together <a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/" title="">the invitation for T-SQL Tuesday #202</a>, I wasn&#8217;t sure what kind of stories would come out of it.</p>


<div class="wp-block-image">
<figure class="alignright size-full is-resized"><img loading="lazy" decoding="async" width="420" height="420" src="https://marlonribunal.com/wp-content/uploads/2026/08/TSQL_Tuesday_Logo.png" alt="T-SQL Tuesday" class="wp-image-2872" style="width:218px;height:auto" srcset="https://marlonribunal.com/wp-content/uploads/2026/08/TSQL_Tuesday_Logo.png 420w, https://marlonribunal.com/wp-content/uploads/2026/08/TSQL_Tuesday_Logo-300x300.png 300w, https://marlonribunal.com/wp-content/uploads/2026/08/TSQL_Tuesday_Logo-150x150.png 150w" sizes="auto, (max-width: 420px) 100vw, 420px" /></figure>
</div>


<p class="wp-block-paragraph">The topic was simple:</p>



<p class="wp-block-paragraph"><strong>That one SQL Server outage you&#8217;ll never forget.</strong></p>



<p class="wp-block-paragraph">I expected stories about bad queries, failed deployments, storage problems, or maybe a database that decided to have a very bad day. What I got was much more interesting.</p>



<p class="wp-block-paragraph">There were stories about ransomware, corrupted databases, deleted storage, power and cooling failures, an identity column reaching its limit, and even a floppy disk. A server Meltdown too.</p>



<p class="wp-block-paragraph">Some of these outages lasted hours. Others lasted days or even weeks.</p>



<p class="wp-block-paragraph">And what I really enjoyed was that most of these stories weren&#8217;t just about what went wrong. They were about what people learned afterward.</p>



<p class="wp-block-paragraph">Here are the stories I was able to collect.</p>



<h2 class="wp-block-heading">Deborah Melkin: Sometimes a Floppy Disk Is All It Takes</h2>



<p class="wp-block-paragraph">Deborah Melkin shared a story from earlier in her career involving a server reboot that went very wrong. A bootable floppy disk had been left in the server. It contained an <code>fdisk /mbr</code> command. The server was rebooted, the command ran, and suddenly they had a much bigger problem than they expected. </p>



<p class="wp-block-paragraph">The team had to find another server, reinstall SQL Server, and restore the databases from backup. The lesson seems obvious now, but that&#8217;s one thing I like about outage stories. Things that seem obvious after the fact aren&#8217;t always obvious when you&#8217;re standing in the middle of the problem. </p>



<p class="wp-block-paragraph">Sometimes the lesson is simply to understand what is actually sitting in or connected to the server before you reboot it. And, of course, make sure your backups are somewhere other than the server you&#8217;re trying to recover.</p>



<p class="wp-block-paragraph"><a href="https://debthedba.wordpress.com/2026/09/08/t-sql-tuesday-202-the-outage-i-wont-forget/">Read Deborah&#8217;s full story</a></p>



<h2 class="wp-block-heading">Andy Yun: The Outages That Live in Infamy</h2>



<p class="wp-block-paragraph">Andy Yun shares two non-SQL Server outages before getting to his SQL Server story. The first was when a backhoe literally dug up his company&#8217;s T1 line, leaving them without Internet for most of the day. </p>



<p class="wp-block-paragraph">The second happened at a software company that supported market traders, where executives chose not to have a backup Internet connection after moving the office to VoIP. When the Internet went down, the entire office, call center, and data center were effectively offline, including their phones. </p>



<p class="wp-block-paragraph">Both stories reinforced the same lesson: <strong>single points of failure hurt</strong>. </p>



<p class="wp-block-paragraph">His SQL Server outage happened while Andy and another DBA were at PASS Summit, when a SAN administrator accidentally deleted the production transaction-log LUN for an instance with several hundred databases and several terabytes of data. Fortunately, their backups were good, and Andy used <code>sp_restoregene</code> to quickly generate the restore commands. </p>



<p class="wp-block-paragraph">They initially tried four parallel restores, but the SAN couldn&#8217;t handle the load, so they stopped and worked with the business to prioritize the databases. The full recovery took three or four days. </p>



<p class="wp-block-paragraph">What Andy realized afterward was that while they had tested restores for CHECKDB, they had never tested a full-instance restore at that scale. The experience also made him realize how important it was to understand the storage and infrastructure that your disaster recovery plan depends on.</p>



<p class="wp-block-paragraph"><a href="https://sqlbek.wordpress.com/2026/09/08/t-sql-tuesday-202-the-outages-that-live-in-infamy/">Read Andy&#8217;s full story</a></p>



<h2 class="wp-block-heading">Aaron Bertrand: When an INT Runs Out</h2>



<p class="wp-block-paragraph">Aaron Bertrand&#8217;s story is a good reminder that capacity problems aren&#8217;t always about disk space, memory, or CPU. In this case, an identity column reached the maximum value for an <code>int</code>. The result was an outage at Stack Overflow. The immediate solution wasn&#8217;t to change the column to <code>bigint</code>. </p>



<p class="wp-block-paragraph">That would have been much more difficult to do during a live production outage. Instead, the identity was reseeded into the negative range, buying the team years of additional capacity. Problem solved. Until it happened again. A later operation involving <code>IDENTITY_INSERT</code> caused the identity value to move toward the positive limit again. So the team had another outage. And they reseeded it again. </p>



<p class="wp-block-paragraph">I liked this story because it shows how an emergency fix can create another problem if the underlying issue isn&#8217;t eventually addressed. It also reminded me that we tend to think about capacity in terms of infrastructure. But data types have limits too. Sometimes the thing running out of room isn&#8217;t the disk.</p>



<p class="wp-block-paragraph"><a href="https://sqlperformance.com/2026/09/sql-performance/t-sql-tuesday-202-memorable-outages">Read Aaron&#8217;s full story</a></p>



<h2 class="wp-block-heading">Rob Farley: When Corruption Leaves You With Very Few Options</h2>



<p class="wp-block-paragraph">Rob Farley wrote about an outage involving a bad disk controller that corrupted hundreds of database pages and even affected some backup files. This was one of those situations where the normal recovery path wasn&#8217;t enough. Rob and the customer&#8217;s CTO started looking at the database table by table, using clustered indexes, nonclustered indexes, <code>DBCC PAGE</code>, older backups, and other sources of information to reconstruct what they could. </p>



<p class="wp-block-paragraph">One of the interesting parts of the story was discovering that a nonclustered index could still contain information that was missing from the corrupted clustered index. That meant even damaged parts of the database could potentially be useful during recovery. </p>



<p class="wp-block-paragraph">Eventually, they were able to rebuild the tables and indexes and get the system back online. Reading this made me think about how different troubleshooting becomes when you&#8217;re no longer trying to find the best query plan or fix a blocking problem. When you&#8217;re dealing with serious corruption, you&#8217;re looking for <strong>anything that can help you recover the data</strong>.</p>



<p class="wp-block-paragraph"><a href="https://lobsterpot.com.au/blog/2026/09/08/outages-to-remember/">Read Rob&#8217;s full story</a></p>



<h2 class="wp-block-heading">Vlad Drumea: Two Weeks of Ransomware Recovery</h2>



<p class="wp-block-paragraph">Vlad Drumea shared probably one of the biggest incidents in this collection. His organization was hit by Ryuk ransomware in 2020. More than 60 SQL Server instances across more than 30 VMs were involved. Recovery took more than two weeks. This wasn&#8217;t simply a matter of restoring a database. </p>



<p class="wp-block-paragraph">The environment itself had to be treated as compromised. Vlad described rebuilding VMs, recreating SQL Server directories, restoring system databases, restoring user databases, dealing with reinfection, fixing broken LSN chains, and rebuilding a VM from scratch. There was also a lot of automation involved using PowerShell, T-SQL, and dbatools. What really stuck with me was the human side of this story. </p>



<p class="wp-block-paragraph">Recovery involved 16-hour workdays for more than two weeks, and Vlad talks about the burnout that followed. We spend a lot of time talking about backups, DR, security, and automation. Those things matter. But there are also people sitting in front of those computers at 2 AM trying to get a business back online. That&#8217;s part of the story too.</p>



<p class="wp-block-paragraph"><a href="https://vladdba.com/2026/09/08/t-sql-tuesday-202-sql-server-ransomware-recovery/">Read Vlad&#8217;s full story</a></p>



<h2 class="wp-block-heading">Jeff Taylor: SQL Server on Fire, Literally!</h2>



<p class="wp-block-paragraph">Jeff Taylor shared two stories involving infrastructure problems. The first started with a power outage in an office that had effectively become a small data center. The servers had battery backup. The air conditioning didn&#8217;t. As the room heated up, the team started using fans and eventually began shutting servers down to keep the hardware from being damaged. </p>



<p class="wp-block-paragraph">The temperature eventually approached 120°F. That incident resulted in a much larger infrastructure redesign, including better cooling, battery backup for the cooling, a generator, and fire suppression. </p>



<p class="wp-block-paragraph">Then there was another incident involving a Dell server where Jeff was replacing memory and a drive. After powering it back on, he saw a flash. Then smoke. The problem apparently involved an iSCSI cable that had been damaged during the earlier heat incident and eventually shorted when the equipment was moved. </p>



<p class="wp-block-paragraph">It&#8217;s a good reminder that SQL Server doesn&#8217;t operate in a vacuum. Power, cooling, storage, networking, and the physical environment are all part of keeping a database available.</p>



<p class="wp-block-paragraph"><a href="https://www.jefftaylor.io/post/t-sql-tuesday-202-the-two-outages-i-won-t-ever-forget">Read Jeff&#8217;s full story</a></p>



<h2 class="wp-block-heading">Edwin Sarmiento: When the Windows XP Image Wiped Out SQL Server</h2>



<p class="wp-block-paragraph">Edwin Sarmiento shared a story from a System Center deployment project where he was responsible for building a ConfigMgr environment for a healthcare company. To keep the deployment isolated, he placed ConfigMgr on its own network and set up a separate SQL Server. </p>



<p class="wp-block-paragraph">During testing, he scheduled a Windows XP image deployment to run against some demo virtual machines. The problem was an incorrect IP address range. Instead of deploying the image to the demo VMs, it deployed to the SQL Server machine and wiped out the entire server. </p>



<p class="wp-block-paragraph">Edwin actually discovered the problem after receiving a 6:15 AM alert that SQL Server was down, eventually logging in to find the SQL Server machine displaying the Windows XP desktop. Fortunately, this was an isolated environment and there was no disruption to the customer&#8217;s normal business operations. </p>



<p class="wp-block-paragraph">What stood out to me about Edwin&#8217;s story is that his biggest lesson wasn&#8217;t about ConfigMgr or SQL Server. It was about the people involved, the decisions they make, and the importance of planning for what can go wrong before it does.</p>



<p class="wp-block-paragraph"><a href="https://learnsqlserverhadr.com/tsql-tuesday-2026a/">Read Edwin&#8217;s full story</a></p>



<h2 class="wp-block-heading">Thomas Rushton: When the Server Room Gets Too Hot</h2>



<p class="wp-block-paragraph">The Lone DBA shared a story about a server room in an old Victorian mill building that overheated after the air conditioning failed during a hot summer weekend. </p>



<p class="wp-block-paragraph">The servers were shut down, and after things cooled down, most of them came back online without any obvious problems. One server, however, kept crashing intermittently. They patched it, updated drivers, replaced the memory, HBAs, CPUs, and even the storage, but nothing fixed the problem. </p>



<p class="wp-block-paragraph">Eventually, while replacing the motherboard, an engineer discovered that a daughterboard had partially melted during the overheating event, causing an intermittent short circuit. It&#8217;s a good reminder that a server room getting too hot isn&#8217;t just a temporary availability problem. It can cause physical hardware damage that may not show up until much later.</p>



<p class="wp-block-paragraph"><a href="https://thelonedba.wordpress.com/2026/09/08/t-sql-tuesday-202-mysterious-outages/">Read The Lone DBA&#8217;s full story</a></p>



<h2 class="wp-block-heading">Andy Levy: When Your Database Time Travels</h2>



<p class="wp-block-paragraph">Andy Levy&#8217;s outage happened while he was away for the weekend and started with more than 250 notifications on his phone. His two-node SQL Server Failover Cluster Instance had repeatedly failed over, and both nodes had gone offline. When he checked the databases, he discovered that roughly two months of work had disappeared. </p>



<p class="wp-block-paragraph">He shut down SQL Server to prevent things from getting worse and began working with his team on recovery. They ultimately restored the databases from backups to a cold spare SQL Server, getting the critical systems back online within a few hours. The postmortem revealed that a storage move two months earlier had left the two cluster nodes pointing to different copies of the virtual disks. Everything appeared fine until patching rebooted both nodes and caused the cluster to fail over to the VM connected to the older copy of the storage. </p>



<p class="wp-block-paragraph">The databases had essentially <strong>“time traveled”</strong> two months into the past. What I liked about this story is how many small things had to line up for this to happen, and how weekly test restores, off-site backups, backed-up TDE certificates, and regular <code>Export-DbaInstance</code> scripts made the recovery possible.</p>



<p class="wp-block-paragraph"><a href="https://flxsql.com/2026/09/08/t-sql-tuesday-202-that-one-outage/">Read Andy&#8217;s full story</a></p>



<h2 class="wp-block-heading">Chad Callihan: What Time Is It?</h2>



<p class="wp-block-paragraph">Chad Callihan shared a deployment that appeared to go perfectly, only for users to start reporting later that morning that some data had the wrong times. Some records that should have been stored in local time were being saved in UTC, while other records were correct. </p>



<p class="wp-block-paragraph">The problem wasn&#8217;t SQL Server itself, but another part of the release. Once identified, they were able to stop the problem, but cleaning up the incorrect data became the bigger challenge. Their environment had multiple time zones, with different tables, databases, logs, and error messages using different time references. Figuring out which records had the wrong time without changing the ones that were already correct made the cleanup particularly difficult. </p>



<p class="wp-block-paragraph">The outage itself wasn&#8217;t very long, but Chad describes the cleanup as one of the worst parts of the experience. It&#8217;s a good reminder that deployments can appear successful while still leaving behind problems that may not show up until users start working with the data.</p>



<p class="wp-block-paragraph"><a href="https://callihandata.com/2026/09/08/t-sql-">Read Chad&#8217;s full story</a></p>



<h2 class="wp-block-heading">Rebecca Lewis: When SQL Slammer Took Down Both Data Centers</h2>



<p class="wp-block-paragraph">Rebecca Lewis takes us back to January 2003 and the SQL Slammer outbreak. Her organization had a primary data center in Chicago and a DR site in New York, but the worm came in through an approved VPN connection and quickly spread across the internal network. The resulting traffic overwhelmed their routers, eventually taking down both sites. </p>



<p class="wp-block-paragraph">More than 400 physical servers had to be recovered, one at a time, while keeping clean machines isolated from infected ones. The IT and DBA teams worked through the weekend and had everything recovered by about 4 AM Monday, just in time for the market open. What stood out to me was that geographic redundancy didn&#8217;t help when the same problem could reach both locations. </p>



<p class="wp-block-paragraph">The firewall had done its job, but the threat came through a legitimate connection that was already inside the network. It&#8217;s a great reminder that having a DR site doesn&#8217;t necessarily protect you from every kind of failure.</p>



<p class="wp-block-paragraph"><a href="https://www.sqlfingers.com/2026/09/t-sql-tuesday-202-invitation-that-one.html">Read Rebecca&#8217;s full story</a></p>



<h2 class="wp-block-heading">M G: A Comment That Deserved to Be Part of the Roundup</h2>



<p class="wp-block-paragraph">A person who goes by their initial M G don&#8217;t have a blog, but left a detailed comment on my invitation. I thought the story was too interesting to leave out. </p>



<p class="wp-block-paragraph">The incident involved SQL Server 2016 and a SharePoint database with around 15 million rows and more than 850 GB of binary data. Three databases were repaired, but the fourth became the real problem. There were hundreds of suspect pages, a corrupted clustered index that was also the primary key, and a <code>DBCC CHECKTABLE ... REPAIR</code> operation that had been running for weeks and failing. </p>



<p class="wp-block-paragraph">What caught my attention was the eventual workaround. Changing the database&#8217;s <code>PAGE_VERIFY</code> setting from <code>CHECKSUM</code> to <code>OFF</code> allowed the primary key to be dropped. That exposed another problem: SharePoint had accumulated roughly 90,000 duplicate elements. This is exactly the kind of kind of troubleshooting story that is difficult to forget because there isn&#8217;t necessarily a clean checklist that tells you what to do next. You investigate. You try something. You learn something new. Then you try again. And sometimes the solution comes from a place you weren&#8217;t expecting.</p>



<h2 class="wp-block-heading">What I Took Away From These Stories</h2>



<p class="wp-block-paragraph">After reading through all of these, I noticed something. The actual cause of the outage was often not SQL Server itself. It was the environment around SQL Server.</p>



<p class="wp-block-paragraph">A floppy disk. A SAN administrator deleting a LUN. An identity value reaching its limit. A bad disk controller. Ransomware. A lack of cooling. Corruption inside a SharePoint database.</p>



<p class="wp-block-paragraph">These are very different problems, but they have something in common.</p>



<p class="wp-block-paragraph"><strong>You don&#8217;t always know what the outage is going to look like until you&#8217;re already in it.</strong></p>



<p class="wp-block-paragraph">That&#8217;s probably why these stories are useful. You can study SQL Server performance. You can learn backup and restore. You can learn Availability Groups. You can learn PowerShell and dbatools. You can learn monitoring. But eventually, something unexpected is going to happen.</p>



<p class="wp-block-paragraph">The best thing we can do is learn from people who have already been there.</p>



<p class="wp-block-paragraph">And that&#8217;s what I really liked about this month&#8217;s T-SQL Tuesday. These weren&#8217;t polished success stories. They were stories about things going wrong.</p>



<p class="wp-block-paragraph">And those are often the stories I remember the longest.</p>



<p class="wp-block-paragraph">Thank you to everyone who took the time to participate in T-SQL Tuesday #202, whether you wrote a full post or shared your experience in the comments.</p>



<p class="wp-block-paragraph">And thank you to Steve Jones for giving me the opportunity to host this month&#8217;s T-SQL Tuesday.</p>



<p class="wp-block-paragraph">Until the next outage&#8230;</p>



<p class="wp-block-paragraph">No, God forbids. It ould be yours, and hopefully the stories above give you the resolution route.</p><p>The post <a href="https://marlonribunal.com/t-sql-tuesday-202-sql-server-outage-youll-never-forget-a-roundup/">T-SQL Tuesday #202 SQL Server Outage You’ll Never Forget: A Roundup</a> first appeared on <a href="https://marlonribunal.com">SQL, Code, Coffee, Etc.</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://marlonribunal.com/t-sql-tuesday-202-sql-server-outage-youll-never-forget-a-roundup/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>T-SQL Tuesday #202 Invitation: That One SQL Server Outage You’ll Never Forget</title>
		<link>https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/</link>
					<comments>https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/#comments</comments>
		
		<dc:creator><![CDATA[Marlon Ribunal]]></dc:creator>
		<pubDate>Tue, 01 Sep 2026 07:05:00 +0000</pubDate>
				<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[#tsql2sday]]></category>
		<guid isPermaLink="false">https://marlonribunal.com/?p=2943</guid>

					<description><![CDATA[<p>I am excited to host T-SQL Tuesday for the first time. I want to hear about that one outage that stands out in your memory. We all have incidents that stay with us long after the servers are back up and things have returned to normal. I’m looking forward to hearing those stories and seeing what we can learn from each other. <a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/">T-SQL Tuesday #202 Invitation: That One SQL Server Outage You’ll Never Forget</a> first appeared on <a href="https://marlonribunal.com">SQL, Code, Coffee, Etc.</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph"><em><strong>Note: This is the invitation for T-SQL Tuesday #202. Your post should go live on September 8, 2026.</strong></em> <em><strong>All posts must be posted by 23:59 Pacific Time. Include the T-SQL Tuesday logo in your post and link it back to this invitation.</strong></em> <em><strong>Use the #tsql2sday hashtag when sharing on social media.</strong></em></p>



<div class="wp-block-media-text is-stacked-on-mobile"><figure class="wp-block-media-text__media"><img loading="lazy" decoding="async" width="420" height="420" src="https://marlonribunal.com/wp-content/uploads/2026/08/TSQL_Tuesday_Logo.png" alt="T-SQL Tuesday" class="wp-image-2872 size-full" srcset="https://marlonribunal.com/wp-content/uploads/2026/08/TSQL_Tuesday_Logo.png 420w, https://marlonribunal.com/wp-content/uploads/2026/08/TSQL_Tuesday_Logo-300x300.png 300w, https://marlonribunal.com/wp-content/uploads/2026/08/TSQL_Tuesday_Logo-150x150.png 150w" sizes="auto, (max-width: 420px) 100vw, 420px" /></figure><div class="wp-block-media-text__content">
<p class="wp-block-paragraph">If you have been working with SQL Server for a while, chances are you have at least one outage that you still remember clearly. It might have happened years ago, and you probably still remember what time it happened, how you found out, what you were doing when the page came in, and what you had to do to get things back to normal.</p>
</div></div>



<p class="wp-block-paragraph">I am excited to host T-SQL Tuesday for the first time. I want to hear about that one outage that stands out in your memory. We all have incidents that stay with us long after the servers are back up and things have returned to normal. I’m looking forward to hearing those stories and seeing what we can learn from each other.</p>



<h3 class="wp-block-heading">That One SQL Server Outage You’ll Never Forget</h3>



<p class="wp-block-paragraph">Tell us about your most memorable SQL Server outage. It could have been a midnight page, a failed failover, a runaway query, a storage problem, a bad deployment, a server that simply would not come back up, or something else that brought production to a stop.</p>



<p class="wp-block-paragraph">I&#8217;m interested in the whole story. What happened? How did you discover the problem? What did you check first? What did you try that worked, and what didn&#8217;t? How did you eventually get things back to normal?</p>



<p class="wp-block-paragraph">Most importantly, what did you learn from the experience?</p>



<p class="wp-block-paragraph">You don&#8217;t have to share the biggest outage you&#8217;ve ever dealt with. Maybe it was a relatively small incident that changed the way you approach backups, monitoring, failover, capacity planning, change management, or troubleshooting. Maybe it exposed a weakness in your environment that you didn&#8217;t know was there. Maybe it taught you something that you have carried with you throughout your career.</p>



<p class="wp-block-paragraph">Share as much of the story as you can, including the things you wish you had known before the outage happened.</p>



<p class="wp-block-paragraph">Since September is <strong>Labor Day</strong> month here in the US (September 7, 2026), I thought it would also be a good opportunity to recognize the people behind these systems. You can make your post as technical as you want, or you can focus more on the human side of the experience. After all, keeping databases online is not just about the technology. There are people behind those systems who have to respond when things go wrong, sometimes at the most inconvenient time.</p>



<h2 class="wp-block-heading">My Own Outage Story</h2>



<p class="wp-block-paragraph">I have one of these stories myself, and it is an outage I don&#8217;t think I will ever forget because of the circumstances surrounding it.</p>



<p class="wp-block-paragraph">I wrote about it in my blog post, <a href="https://marlonribunal.com/reflections-on-the-life-of-a-dba/">Reflections on the Life of a DBA</a>. It was a cold January evening, and I was at a black-tie party when the alerts started coming in. My phone was lighting up with Splunk On-Call alerts and Teams messages because an important SQL Server had gone down.</p>



<p class="wp-block-paragraph">I had my work laptop with me, as I almost always did, so I found a corner in the busy kitchen, opened the laptop, and started working on the problem while everyone else continued with the evening. I still remember sitting there in a black suit with my laptop, troubleshooting SQL Server in the middle of a busy kitchen while a celebration was happening around me.</p>



<p class="wp-block-paragraph">That is one of those moments from my DBA career that has stayed with me, and it is part of what inspired me to choose this month&#8217;s topic. We spend a lot of time talking about SQL Server features, performance tuning, architecture, and best practices, but some of the lessons that stay with us come from the times when something actually went wrong and we had to figure it out.</p>



<p class="wp-block-paragraph">Now I&#8217;m curious about yours.</p>



<h2 class="wp-block-heading">A Little T-SQL Tuesday History</h2>



<p class="wp-block-paragraph">T-SQL Tuesday started back in 2009 when Adam Machanic invited SQL Server bloggers to write about a common topic and publish their posts on the same day. What started as a simple way for the community to share different perspectives has become a long-running SQL Server tradition.</p>



<p class="wp-block-paragraph">Today, Steve Jones coordinates the event, and the posts are collected in the <a href="https://tsqltuesday.com/the-archive/"><strong>T-SQL Tuesday archive</strong></a>. Thanks, Steve, for selecting me to host this month&#8217;s T-SQL Tuesday. If you have never gone through the archive, there is a lot of good SQL Server knowledge and real-world experience in there.</p>



<p class="wp-block-paragraph">One of the things I like about T-SQL Tuesday is seeing how people from different backgrounds approach the same topic. You often learn something new, and sometimes you find a story that sounds very familiar.</p>



<h2 class="wp-block-heading">The Rules</h2>



<p class="wp-block-paragraph">The rules for this month&#8217;s T-SQL Tuesday are pretty simple.</p>



<p class="wp-block-paragraph"><strong>1. Write a blog post about the topic.</strong></p>



<p class="wp-block-paragraph">Write about your most memorable SQL Server outage and share the story, the recovery, and the lessons you took away from it.</p>



<p class="wp-block-paragraph"><strong>2. Publish your post on Tuesday, September 8, 2026.</strong></p>



<p class="wp-block-paragraph">That&#8217;s the publishing date for T-SQL Tuesday #202.</p>



<p class="wp-block-paragraph"><strong>3. Link back to this invitation.</strong></p>



<p class="wp-block-paragraph">Please include a link to this invitation in your post so readers can find the topic and discover the other posts participating in this month&#8217;s T-SQL Tuesday.</p>



<p class="wp-block-paragraph"><strong>4. Add your post to the comments.</strong></p>



<p class="wp-block-paragraph">Once your post is published, leave the link in the comments below so I can find it and include it in the roundup.</p>



<p class="wp-block-paragraph"><strong>5. Keep company and customer information confidential.</strong></p>



<p class="wp-block-paragraph">Please don&#8217;t include anything that shouldn&#8217;t be publicly shared, such as customer information, credentials, server names, IP addresses, or other sensitive details. Change the names and details as necessary. The goal is to share what we learned from the experience.</p>



<h2 class="wp-block-heading">Now Tell Us Your Story</h2>



<p class="wp-block-paragraph">I&#8217;m looking forward to reading these because outages are where a lot of our best lessons come from. The technical details are important, but I&#8217;m also interested in what happened around the technical problem, how you approached the situation, what decisions you had to make under pressure, and what you changed afterward.</p>



<p class="wp-block-paragraph">Most of us have had that one SQL Server incident that made us learn something the hard way.</p>



<p class="wp-block-paragraph">Maybe you were at home. Maybe you were in the office. Maybe you were asleep. Maybe, like me, you were at a party sitting in a kitchen with a laptop.</p>



<p class="wp-block-paragraph"><strong>What&#8217;s yours?</strong></p>



<p class="wp-block-paragraph">Write about it, share it with the SQL Server community, and let&#8217;s see what we can learn from each other&#8217;s outage stories.</p>



<p class="wp-block-paragraph"></p>



<div class="wp-block-comments"><h2 id="comments" class="wp-block-comments-title">17 responses to &#8220;T-SQL Tuesday #202 Invitation: That One SQL Server Outage You’ll Never Forget&#8221;</h2>

<ol class="wp-block-comment-template"><li id="comment-13427" class="pingback even thread-even depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="https://marlonribunal.com/t-sql-tuesday-202-sql-server-outage-youll-never-forget-a-roundup/" target="_self" >T-SQL Tuesday #202 SQL Server Outage You’ll Never Forget: A Roundup &#8211; SQL, Code, Coffee, Etc.</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-18T22:43:04-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13427">09/18/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>[&#8230;] I put together the invitation for T-SQL Tuesday #202, I wasn&#8217;t sure what kind of stories would come out of [&#8230;]</p>
</div>

</div>
</div>

</li><li id="comment-13421" class="comment odd alt thread-odd thread-alt depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"><img alt='Rebecca Avatar' src='https://secure.gravatar.com/avatar/180e7604057bbab803b013c38ec90caf102aeab7ac16e4dbd841945fbf479b35?s=40&#038;d=retro&#038;r=g' srcset='https://secure.gravatar.com/avatar/180e7604057bbab803b013c38ec90caf102aeab7ac16e4dbd841945fbf479b35?s=80&#038;d=retro&#038;r=g 2x' class='avatar avatar-40 photo wp-block-avatar__image' height='40' width='40'  style="border-radius:20px;"/></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="https://www.sqlfingers.com/" target="_self" >Rebecca</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-11T06:08:38-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13421">09/11/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>Sorry, Marlon.  I am a few days late, but still something I wanted to share.  <a href="https://www.sqlfingers.com/2026/09/t-sql-tuesday-202-invitation-that-one.html" rel="nofollow ugc">https://www.sqlfingers.com/2026/09/t-sql-tuesday-202-invitation-that-one.html</a></p>
</div>

</div>
</div>

</li><li id="comment-13418" class="pingback even thread-even depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="https://learnsqlserverhadr.com/tsql-tuesday-2026a/" target="_self" >T-SQL Tuesday #202 – That One SQL Server Outage I&#8217;ll Never Forget &#8211; Learn SQL Server High Availability &amp; Disaster Recovery</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-08T15:25:05-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13418">09/08/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>[&#8230;] started. This month&#8217;s episode is hosted by Marlon Ribunal (blog | Twitter). The topic: That One SQL Server Outage You’ll Never Forget. As a high availability and disaster recovery expert, I&#8217;ve had a front-row seat on the [&#8230;]</p>
</div>

</div>
</div>

</li><li id="comment-13417" class="comment odd alt thread-odd thread-alt depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"><img alt='Chad Callihan Avatar' src='https://secure.gravatar.com/avatar/ee372686480b3fb4af818bb0abb35807628a13c85346d5be44ad65f2d51b9c8d?s=40&#038;d=retro&#038;r=g' srcset='https://secure.gravatar.com/avatar/ee372686480b3fb4af818bb0abb35807628a13c85346d5be44ad65f2d51b9c8d?s=80&#038;d=retro&#038;r=g 2x' class='avatar avatar-40 photo wp-block-avatar__image' height='40' width='40'  style="border-radius:20px;"/></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="https://callihandata.com/" target="_self" >Chad Callihan</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-08T15:23:12-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13417">09/08/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>Thanks for hosting!  My post is here <a href="https://callihandata.com/2026/09/08/t-sql-tuesday-202-an-unforgettable-outage/" rel="nofollow ugc">https://callihandata.com/2026/09/08/t-sql-tuesday-202-an-unforgettable-outage/</a></p>
</div>

</div>
</div>

</li><li id="comment-13416" class="comment even thread-even depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"><img alt='Edwin M Sarmiento Avatar' src='https://secure.gravatar.com/avatar/4d43b4b146be31d91b573cf827139607ab7a493ce3a8e22a9891eeaa4c353a9f?s=40&#038;d=retro&#038;r=g' srcset='https://secure.gravatar.com/avatar/4d43b4b146be31d91b573cf827139607ab7a493ce3a8e22a9891eeaa4c353a9f?s=80&#038;d=retro&#038;r=g 2x' class='avatar avatar-40 photo wp-block-avatar__image' height='40' width='40'  style="border-radius:20px;"/></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="https://learnsqlserverhadr.com" target="_self" >Edwin M Sarmiento</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-08T14:37:18-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13416">09/08/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>Marlon,</p>
<p>Here&#8217;s my story for this month&#8217;s T-SQL Tuesday</p>
<p><a href="https://learnsqlserverhadr.com/tsql-tuesday-2026a/" rel="nofollow ugc">https://learnsqlserverhadr.com/tsql-tuesday-2026a/</a></p>
</div>

</div>
</div>

</li><li id="comment-13415" class="comment odd alt thread-odd thread-alt depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"><img alt='Thomas Rushton Avatar' src='https://secure.gravatar.com/avatar/b265ffd32916b9ae2e668d9936f0013c90407379cf420a2bf09cae51f263df60?s=40&#038;d=retro&#038;r=g' srcset='https://secure.gravatar.com/avatar/b265ffd32916b9ae2e668d9936f0013c90407379cf420a2bf09cae51f263df60?s=80&#038;d=retro&#038;r=g 2x' class='avatar avatar-40 photo wp-block-avatar__image' height='40' width='40'  style="border-radius:20px;"/></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="http://thelonedba.wordpress.com" target="_self" >Thomas Rushton</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-08T14:30:59-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13415">09/08/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>A hasty contribution &#8211; apologies for any formatting issues, spelling mistooks, lack of coherence&#8230;  it&#8217;s been a while since I did one of these, and I only spotted the invitation and gained inspiration an hour or so ago&#8230;</p>
<p><a href="https://thelonedba.wordpress.com/2026/09/08/t-sql-tuesday-202-mysterious-outages/" rel="nofollow ugc">https://thelonedba.wordpress.com/2026/09/08/t-sql-tuesday-202-mysterious-outages/</a></p>
</div>

</div>
</div>

</li><li id="comment-13414" class="comment even thread-even depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"><img alt='Andy Levy Avatar' src='https://secure.gravatar.com/avatar/1a00f4f0314fa605eb3d04bd0fb45741e89348bcd9ac522f761235659fcd8a7c?s=40&#038;d=retro&#038;r=g' srcset='https://secure.gravatar.com/avatar/1a00f4f0314fa605eb3d04bd0fb45741e89348bcd9ac522f761235659fcd8a7c?s=80&#038;d=retro&#038;r=g 2x' class='avatar avatar-40 photo wp-block-avatar__image' height='40' width='40'  style="border-radius:20px;"/></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="https://flxsql.com/" target="_self" >Andy Levy</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-08T12:08:39-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13414">09/08/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>Thanks for hosting! Here&#8217;s my tale &#8211; <a href="https://flxsql.com/2026/09/08/t-sql-tuesday-202-that-one-outage/" rel="nofollow ugc">https://flxsql.com/2026/09/08/t-sql-tuesday-202-that-one-outage/</a></p>
</div>

</div>
</div>

</li><li id="comment-13413" class="comment odd alt thread-odd thread-alt depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"><img alt='Deborah Melkin Avatar' src='https://secure.gravatar.com/avatar/e645eff8594cf657c3d1cbefe5cd2174b173b19613fbb18241aaa79fcf7d0e63?s=40&#038;d=retro&#038;r=g' srcset='https://secure.gravatar.com/avatar/e645eff8594cf657c3d1cbefe5cd2174b173b19613fbb18241aaa79fcf7d0e63?s=80&#038;d=retro&#038;r=g 2x' class='avatar avatar-40 photo wp-block-avatar__image' height='40' width='40'  style="border-radius:20px;"/></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="https://debthedba.wordpress.com" target="_self" >Deborah Melkin</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-08T11:57:32-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13413">09/08/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>Thanks for hosting! Here&#8217;s my contribution: <a href="https://debthedba.wordpress.com/2026/09/08/t-sql-tuesday-202-the-outage-i-wont-forget/" rel="nofollow ugc">https://debthedba.wordpress.com/2026/09/08/t-sql-tuesday-202-the-outage-i-wont-forget/</a></p>
</div>

</div>
</div>

</li><li id="comment-13412" class="comment even thread-even depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"><img alt='Andy &quot;SQLBek&quot; Yun Avatar' src='https://secure.gravatar.com/avatar/f45ba30be0f9d818842c8e5e9c276a50b4460bf38d14b378974a3a531f16a9db?s=40&#038;d=retro&#038;r=g' srcset='https://secure.gravatar.com/avatar/f45ba30be0f9d818842c8e5e9c276a50b4460bf38d14b378974a3a531f16a9db?s=80&#038;d=retro&#038;r=g 2x' class='avatar avatar-40 photo wp-block-avatar__image' height='40' width='40'  style="border-radius:20px;"/></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size">Andy &#8220;SQLBek&#8221; Yun</div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-08T11:48:13-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13412">09/08/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>Thanks for hosting!  Here&#8217;s my contribution! <a href="https://sqlbek.wordpress.com/2026/09/08/t-sql-tuesday-202-the-outages-that-live-in-infamy/" rel="nofollow ugc">https://sqlbek.wordpress.com/2026/09/08/t-sql-tuesday-202-the-outages-that-live-in-infamy/</a></p>
</div>

</div>
</div>

</li><li id="comment-13411" class="pingback odd alt thread-odd thread-alt depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="https://sqlbek.wordpress.com/2026/09/08/t-sql-tuesday-202-the-outages-that-live-in-infamy/" target="_self" >T-SQL Tuesday #202: The Outages That Live in Infamy | Every Byte Counts</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-08T11:47:27-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13411">09/08/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>[&#8230;] This month&#8217;s edition is hosted by Marlon Ribunal, who asks participants to blog about That One SQL Server Outage You&#8217;ll Never Forget. Today, I&#8217;ll share two brief non-SQL Server stories and one SQL Server story, that&#8217;ll [&#8230;]</p>
</div>

</div>
</div>

</li><li id="comment-13410" class="pingback even thread-even depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="https://debthedba.wordpress.com/2026/09/08/t-sql-tuesday-202-the-outage-i-wont-forget/" target="_self" >T-SQL Tuesday #202 &#8211; The Outage I Won&#8217;t Forget &#8211; Deb the DBA</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-08T07:00:48-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13410">09/08/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>[&#8230;] Welcome to another T-SQL Tuesday! This month is hosted by Marlon Ribunal (b). You can find the full invitation here. [&#8230;]</p>
</div>

</div>
</div>

</li><li id="comment-13409" class="comment odd alt thread-odd thread-alt depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"><img alt='Aaron Bertrand Avatar' src='https://secure.gravatar.com/avatar/0315973455aa8ec8137b626224de4b513276b9b5cc19f8edede8b989d485f367?s=40&#038;d=retro&#038;r=g' srcset='https://secure.gravatar.com/avatar/0315973455aa8ec8137b626224de4b513276b9b5cc19f8edede8b989d485f367?s=80&#038;d=retro&#038;r=g 2x' class='avatar avatar-40 photo wp-block-avatar__image' height='40' width='40'  style="border-radius:20px;"/></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="https://sqlblog.org" target="_self" >Aaron Bertrand</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-08T05:23:40-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13409">09/08/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>Thanks Marlon, here&#8217;s my entry:</p>
<p><a href="https://sqlperformance.com/2026/09/sql-performance/t-sql-tuesday-202-memorable-outages" rel="nofollow ugc">https://sqlperformance.com/2026/09/sql-performance/t-sql-tuesday-202-memorable-outages</a></p>
</div>

</div>
</div>

</li><li id="comment-13408" class="comment even thread-even depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"><img alt='Rob Farley Avatar' src='https://secure.gravatar.com/avatar/029940d002b312dbefa4c2c7e7705b1ffcdd700f8632709d9253b89ead47c7be?s=40&#038;d=retro&#038;r=g' srcset='https://secure.gravatar.com/avatar/029940d002b312dbefa4c2c7e7705b1ffcdd700f8632709d9253b89ead47c7be?s=80&#038;d=retro&#038;r=g 2x' class='avatar avatar-40 photo wp-block-avatar__image' height='40' width='40'  style="border-radius:20px;"/></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="https://lobsterpot.com.au/" target="_self" >Rob Farley</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-08T01:36:22-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13408">09/08/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>Hi Marlon. Here&#8217;s mine. <a href="https://lobsterpot.com.au/blog/2026/09/08/outages-to-remember/" rel="nofollow ugc">https://lobsterpot.com.au/blog/2026/09/08/outages-to-remember/</a></p>
</div>

</div>
</div>

</li><li id="comment-13407" class="comment odd alt thread-odd thread-alt depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"><img alt='Vlad Drumea Avatar' src='https://secure.gravatar.com/avatar/6214d5ea6606495924a485ba0016184528fd274b775d5944b651cfed462ae9a5?s=40&#038;d=retro&#038;r=g' srcset='https://secure.gravatar.com/avatar/6214d5ea6606495924a485ba0016184528fd274b775d5944b651cfed462ae9a5?s=80&#038;d=retro&#038;r=g 2x' class='avatar avatar-40 photo wp-block-avatar__image' height='40' width='40'  style="border-radius:20px;"/></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="https://vladdba.com/" target="_self" >Vlad Drumea</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-07T23:48:32-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13407">09/07/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>Hi Marlon,<br />
Thanks for hosting this month&#8217;s tsql2sday!<br />
Here&#8217;s my contribution:<br />
<a href="https://vladdba.com/2026/09/08/t-sql-tuesday-202-sql-server-ransomware-recovery/" rel="nofollow ugc">https://vladdba.com/2026/09/08/t-sql-tuesday-202-sql-server-ransomware-recovery/</a></p>
</div>

</div>
</div>

</li><li id="comment-13406" class="comment even thread-even depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"><img alt='Jeff Taylor Avatar' src='https://secure.gravatar.com/avatar/a2b7c0db8912d5ac77a97edb88c2f1b9c9f07c425ffd4ce6748be9b2468698ba?s=40&#038;d=retro&#038;r=g' srcset='https://secure.gravatar.com/avatar/a2b7c0db8912d5ac77a97edb88c2f1b9c9f07c425ffd4ce6748be9b2468698ba?s=80&#038;d=retro&#038;r=g 2x' class='avatar avatar-40 photo wp-block-avatar__image' height='40' width='40'  style="border-radius:20px;"/></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="https://jefftaylor.io" target="_self" >Jeff Taylor</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-07T21:14:16-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13406">09/07/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>Hi Marlon, thanks for hosting… here is my blog post: <a href="https://www.jefftaylor.io/post/t-sql-tuesday-202-the-two-outages-i-won-t-ever-forget" rel="nofollow ugc">https://www.jefftaylor.io/post/t-sql-tuesday-202-the-two-outages-i-won-t-ever-forget</a></p>
</div>

</div>
</div>

</li><li id="comment-13401" class="comment odd alt thread-odd thread-alt depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"><img alt='M G Avatar' src='https://secure.gravatar.com/avatar/770fb1009ac12fe19070ecde33703f9ecb04e167c2c7acf4c2092ec751ed9ba6?s=40&#038;d=retro&#038;r=g' srcset='https://secure.gravatar.com/avatar/770fb1009ac12fe19070ecde33703f9ecb04e167c2c7acf4c2092ec751ed9ba6?s=80&#038;d=retro&#038;r=g 2x' class='avatar avatar-40 photo wp-block-avatar__image' height='40' width='40'  style="border-radius:20px;"/></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size">M G</div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-03T17:10:54-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13401">09/03/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>I don&#8217;t have a blog, so I&#8217;ll do it here <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br />
&#8220;Why no blog?&#8221;<br />
Because there are SO many already out there &#8211; a majority with exemplary information that is supremely useful, it is impossible to keep up with all of them.  We still need time to sleep and eat and do those chores that need doing without reading and writing the remaining 16-ish hours of the day outside of work.</p>
<p>I&#8217;ve recently run into a corruption issue in SharePoint databases in SQL 2016.<br />
(I&#8217;m guessing that the SQL Services were crashed when the server was turned off after an attack of some form (I&#8217;m not privy to the type of attack).</p>
<p>Anyway, I was able to correct the issues in 3 of the 4 databases, but the last one had hundreds of suspect pages (according to the table in MSDB) in a table of 15m rows (not huge) but it contains binary data which blows the single table out to over 850Gb.</p>
<p>I&#8217;ve worked through all of the methods I can find and a CHECKTABLE with the REPAIR option running for 2 weeks and having failed twice as the server either gets rebooted due to automated patching or someone rebooting it because&#8230; they felt like it.</p>
<p>The issue is in the clustered index which is also the primary key.  This means that, because of the CheckSum issues, it will not allow the dropping of the key.  Not in single-access mode nor emergency mode.</p>
<p>No amount of searching revealed a fix that I ultimately attempted on a copy of the database.</p>
<p>So&#8230; what is the fix that I worked out?<br />
Go into the database settings and set the Page Verify option from CHECKSUM to OFF.  Then the primary key can be dropped.</p>
<p>Now it turns out that SharePoint had continued to add values for some 90k elements even though the primary key is indeed unique.  The content of the rows is identical, so removal is going to be interesting but not impossible.</p>
<p>What I&#8217;ll wait for now is someone to say something like &#8220;Oh &#8211; that&#8217;s a common fix!&#8221;.  No&#8230; it&#8217;s not&#8230; that&#8217;s why I put it here.</p>
</div>

</div>
</div>

<ol><li id="comment-13402" class="comment byuser comment-author-marlon bypostauthor even depth-2">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"><img alt='Marlon Ribunal Avatar' src='https://secure.gravatar.com/avatar/8d0b7ecf5c8767c2d8d444064f61d083b37822cd606f858bf03a3ef4fd27c809?s=40&#038;d=retro&#038;r=g' srcset='https://secure.gravatar.com/avatar/8d0b7ecf5c8767c2d8d444064f61d083b37822cd606f858bf03a3ef4fd27c809?s=80&#038;d=retro&#038;r=g 2x' class='avatar avatar-40 photo wp-block-avatar__image' height='40' width='40'  style="border-radius:20px;"/></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="http://marlonribunal.com" target="_self" >Marlon Ribunal</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-09-04T00:21:37-07:00"><a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/comment-page-1/#comment-13402">09/04/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>Thanks for sharing this story. Although this does not count as a blog, I think it&#8217;s worth to be included in the roundup.</p>
</div>

</div>
</div>

</li></ol></li></ol>



</div><p>The post <a href="https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/">T-SQL Tuesday #202 Invitation: That One SQL Server Outage You’ll Never Forget</a> first appeared on <a href="https://marlonribunal.com">SQL, Code, Coffee, Etc.</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://marlonribunal.com/t-sql-tuesday-202-invitation-that-one-sql-server-outage-youll-never-forget/feed/</wfw:commentRss>
			<slash:comments>17</slash:comments>
		
		
			</item>
		<item>
		<title>Demo for Parameter Sniffing and Memory Grant Feedback</title>
		<link>https://marlonribunal.com/demo-for-parameter-sniffing-and-memory-grant-feedback/</link>
		
		<dc:creator><![CDATA[Marlon Ribunal]]></dc:creator>
		<pubDate>Thu, 13 Aug 2026 11:05:00 +0000</pubDate>
				<category><![CDATA[SQL Server]]></category>
		<guid isPermaLink="false">https://marlonribunal.com/?p=2861</guid>

					<description><![CDATA[<p>Disclaimer: The following is built with Claude Code. Just need to justify my $100/mo subscription cost. This was meant for a private demo so I can learn more about parameter sniffing and memory grant, but I decided to open it &#8230; <a href="https://marlonribunal.com/demo-for-parameter-sniffing-and-memory-grant-feedback/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://marlonribunal.com/demo-for-parameter-sniffing-and-memory-grant-feedback/">Demo for Parameter Sniffing and Memory Grant Feedback</a> first appeared on <a href="https://marlonribunal.com">SQL, Code, Coffee, Etc.</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph"><em><strong>Disclaimer</strong>: The following is built with Claude Code. Just need to justify my $100/mo subscription cost. This was meant for a private demo so I can learn more about parameter sniffing and memory grant, but I decided to open it to public. And you may say &#8220;Marlon, this isn&#8217;t you, this is too good.&#8221; Again, I will say it again, originally I was to keep this a private learning doc for me to understand Parameter sniffing. I asked Claude Code to build me a test for param sniffing and memory grant feedback. The following is the result of that after few prompts. You may use this for your own demo or POC. Run at your own risk. The Github Repo info is at the bottom of this post.</em></p>



<p class="has-babed-8-color has-text-color wp-block-paragraph">The stored procedure runs in milliseconds. It has been running in milliseconds for the last two years. Then one morning, it suddenly takes four minutes to complete. No code deployment. No configuration change. Nothing obvious changed. Restart the SQL Server instance, and it goes back to being fast — at least until later in the day.</p>



<p class="wp-block-paragraph">You already know what the first response in the incident channel will be: &#8220;It&#8217;s parameter sniffing.&#8221;</p>



<p class="wp-block-paragraph">And technically, that answer may be correct. But it does not tell you enough to fix the problem.</p>



<p class="wp-block-paragraph">Parameter sniffing is not a single issue. There are different ways this can bite you, but two of the most common ones are easy to confuse.</p>



<p class="wp-block-paragraph">The first is a bad plan choice. SQL Server compiles a plan based on one set of parameter values, but that same plan performs poorly when reused for a different set of values. For example, SQL Server may choose an index seek with hundreds of thousands of key lookups when a scan would have been the better option.</p>



<p class="wp-block-paragraph">The second is a bad memory grant. SQL Server estimates it only needs enough memory for a small number of rows, but the actual query returns hundreds of thousands of rows. The result can be spills to tempdb, poor performance, and unnecessary memory pressure.</p>



<p class="wp-block-paragraph">These two problems can look similar from the outside, but they require different troubleshooting approaches.</p>



<p class="wp-block-paragraph">This is especially important with newer SQL Server features like Memory Grant Feedback. It can help correct inaccurate memory grants, but it does not change a fundamentally bad plan choice. If you do not identify which problem you actually have, you can apply a fix that was never designed to solve the issue.</p>



<p class="has-babed-8-color has-text-color wp-block-paragraph">The goal of this post is to separate these two behaviors, show how they are different, and walk through a demo you can reproduce yourself.</p>



<h2 class="wp-block-heading">Sniffing is a feature</h2>



<p class="wp-block-paragraph">Before getting into the problem, it is important to set the right context. A lot of discussions around parameter sniffing make it sound like a SQL Server defect that Microsoft should have fixed. That is not really the case.</p>



<p class="wp-block-paragraph">When SQL Server compiles a parameterized query, it uses the parameter values that caused the compilation to estimate the number of rows and build a plan. It looks at the statistics, checks the histogram, estimates the expected cardinality, and creates a plan based on that information. That plan is then stored in cache and reused for future executions, even if those executions use very different parameter values.</p>



<p class="wp-block-paragraph">The first part of this process is actually what makes SQL Server perform well. Without parameter sniffing, SQL Server would have to create plans based on generic estimates instead of the actual values being searched. You would end up with a plan that is average for everyone instead of a plan that is optimized for the majority of cases.</p>



<p class="wp-block-paragraph">The problem is not parameter sniffing itself. The problem is reusing a plan when the data distribution does not match the values that plan was originally optimized for.</p>



<p class="wp-block-paragraph">This is where data skew comes into play. If values in a column are evenly distributed, most parameter values will produce similar row counts, and the cached plan will usually work well. Parameter sniffing only becomes a problem when some values return a small number of rows while others return a significantly different number of rows.</p>



<p class="wp-block-paragraph">So the first question should not be, &#8220;How do I disable parameter sniffing?&#8221;</p>



<p class="wp-block-paragraph">The better question is, &#8220;How is the data distributed, and how much skew exists in this column?&#8221;</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#292d3e"><span style="background:#aaafcf;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#292d3e">SQL</span></span><span role="button" tabindex="0" style="color:#babed8;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>SELECT   TOP (20) CustomerID, Rows = COUNT_BIG(*)
FROM     Sales.OrderLines_or_whatever
GROUP BY CustomerID
ORDER BY Rows DESC;
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki material-theme-palenight" style="background-color: #292D3E" tabindex="0"><code><span class="line"><span style="color: #F78C6C">SELECT</span><span style="color: #BABED8">   </span><span style="color: #F78C6C">TOP</span><span style="color: #BABED8"> (</span><span style="color: #F78C6C">20</span><span style="color: #BABED8">) CustomerID, </span><span style="color: #F78C6C">Rows</span><span style="color: #BABED8"> </span><span style="color: #89DDFF">=</span><span style="color: #BABED8"> </span><span style="color: #82AAFF">COUNT_BIG</span><span style="color: #BABED8">(</span><span style="color: #89DDFF">*</span><span style="color: #BABED8">)</span></span>
<span class="line"><span style="color: #F78C6C">FROM</span><span style="color: #BABED8">     Sales.OrderLines_or_whatever</span></span>
<span class="line"><span style="color: #F78C6C">GROUP BY</span><span style="color: #BABED8"> CustomerID</span></span>
<span class="line"><span style="color: #F78C6C">ORDER BY</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">Rows</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">DESC</span><span style="color: #BABED8">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">If the difference between the highest and lowest values is only within an order of magnitude, then data skew is probably not your problem. There is likely something else causing the bad plan choice.</p>



<h2 class="wp-block-heading">Building a demo; thanks, claude</h2>



<p class="wp-block-paragraph">I wanted to demonstrate both failure modes using actual query behavior, which means I needed data with a noticeable skew. The challenge is that standard sample databases are not always useful for demonstrating these types of problems.</p>



<p class="wp-block-paragraph">For this test, I used <strong>Claude Code</strong> to help create the setup script and build the test scenario. WideWorldImporters, Microsoft&#8217;s sample database, was used as the starting point because it contains real order data. However, the data distribution is fairly uniform. Order lines are spread across customers, dates, and stock items. That makes sense for a sample database, but it does not create the conditions needed to demonstrate parameter sensitivity.</p>



<p class="wp-block-paragraph">The skew in this demo is intentional and documented. The script creates <code>Demo.OrderLinesSkewed</code> using WideWorldImporters&#8217; approximately 231,000 existing order lines, then adds another 500,000 rows tied to a single customer. The goal is to create a simple scenario where one customer has a large percentage of the data while most other customers have significantly fewer rows.</p>



<p class="wp-block-paragraph">The customer values are not hardcoded. The script identifies the large customer and the smaller customers from the data and prints them out. This makes the demo more portable because WideWorldImporters installations may not all contain identical data.</p>



<p class="wp-block-paragraph">I prefer demos that are transparent about how the test conditions were created. The important part is not the test data itself. The important part is understanding the SQL Server behavior we are trying to demonstrate.</p>



<p class="wp-block-paragraph">There are three important details in the setup that make this demo work. Each one represents a common reason why performance demos like this can produce misleading results:</p>



<p class="wp-block-paragraph"><strong>The index is narrow on purpose.</strong>&nbsp;A single non-clustered index on&nbsp;<code>CustomerID</code>, no&nbsp;<code>INCLUDE</code>&nbsp;columns:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#292d3e"><span style="background:#aaafcf;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#292d3e">SQL</span></span><span role="button" tabindex="0" style="color:#babed8;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>CREATE NONCLUSTERED INDEX IX_OrderLinesSkewed_CustomerID
    ON Demo.OrderLinesSkewed (CustomerID);
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki material-theme-palenight" style="background-color: #292D3E" tabindex="0"><code><span class="line"><span style="color: #F78C6C">CREATE</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">NONCLUSTERED</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">INDEX</span><span style="color: #BABED8"> IX_OrderLinesSkewed_CustomerID</span></span>
<span class="line"><span style="color: #BABED8">    </span><span style="color: #F78C6C">ON</span><span style="color: #BABED8"> Demo.OrderLinesSkewed (CustomerID);</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">TThe goal is to force SQL Server to make a real choice. It can either use the index and perform key lookups for each row, or decide that scanning the clustered index is the better option. Where SQL Server draws that line is the plan shape side of the problem.</p>



<p class="wp-block-paragraph">If the index is covering, that decision goes away. You may still see a memory grant issue, but you will not see the plan change between executions. The result is a demo that only shows one side of the problem and misses how parameter sensitivity can affect plan selection.</p>



<p class="wp-block-paragraph">The rows are intentionally wide. There is a <code>char(200)</code> filler column, and the stored procedure includes that column in the output. Memory grants are calculated using estimated rows multiplied by estimated row width. If the rows are too narrow, the memory grant behavior is not very interesting.</p>



<p class="wp-block-paragraph">There is also no <code>TOP</code> and no <code>ROW_NUMBER()</code> in this demo. This is an important detail because many demos around this topic accidentally hide the memory grant problem.</p>



<p class="wp-block-paragraph">For example, a query like <code>SELECT TOP (50) ... ORDER BY UnitPrice DESC</code> introduces a <code>Top N Sort</code>. The memory grant for a <code>Top N Sort</code> is based on the number of rows being returned, in this case 50, instead of the total number of rows flowing through the sort. Filtering a <code>ROW_NUMBER()</code> value against a constant can have a similar issue because the optimizer may rewrite it into a <code>Top</code>.</p>



<p class="wp-block-paragraph">In both cases, the memory grant no longer scales with the actual workload. The demo may still run, but it is no longer showing the behavior we are trying to analyze.</p>



<p class="wp-block-paragraph">If you build your own version of this test, check the execution plan and make sure the operator is a <code>Sort</code> and not a <code>Top N Sort</code>. The demo scripts capture the plan after each execution and flag <code>Top N Sort</code> because it changes the behavior being tested.</p>



<p class="wp-block-paragraph">Here&#8217;s the procedure. It is deliberately boring:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#292d3e"><span style="background:#aaafcf;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#292d3e">SQL</span></span><span role="button" tabindex="0" style="color:#babed8;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>CREATE OR ALTER PROCEDURE Demo.usp_CustomerLinesByPrice
    @CustomerID int
AS
BEGIN
    SET NOCOUNT ON;

    SELECT  ol.OrderLineID, ol.OrderID, ol.CustomerID, ol.StockItemID,
            ol.Description, ol.Quantity, ol.UnitPrice, ol.OrderDate,
            ol.Filler
    FROM    Demo.OrderLinesSkewed AS ol
    WHERE   ol.CustomerID = @CustomerID
    ORDER BY ol.UnitPrice DESC, ol.Description;
END
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki material-theme-palenight" style="background-color: #292D3E" tabindex="0"><code><span class="line"><span style="color: #F78C6C">CREATE</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">OR</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">ALTER</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">PROCEDURE</span><span style="color: #BABED8"> Demo.usp_CustomerLinesByPrice</span></span>
<span class="line"><span style="color: #BABED8">    @CustomerID </span><span style="color: #C792EA">int</span></span>
<span class="line"><span style="color: #F78C6C">AS</span></span>
<span class="line"><span style="color: #F78C6C">BEGIN</span></span>
<span class="line"><span style="color: #BABED8">    </span><span style="color: #F78C6C">SET</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">NOCOUNT</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">ON</span><span style="color: #BABED8">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #BABED8">    </span><span style="color: #F78C6C">SELECT</span><span style="color: #BABED8">  ol.OrderLineID, ol.OrderID, ol.CustomerID, ol.StockItemID,</span></span>
<span class="line"><span style="color: #BABED8">            ol.Description, ol.Quantity, ol.UnitPrice, ol.OrderDate,</span></span>
<span class="line"><span style="color: #BABED8">            ol.Filler</span></span>
<span class="line"><span style="color: #BABED8">    </span><span style="color: #F78C6C">FROM</span><span style="color: #BABED8">    Demo.OrderLinesSkewed </span><span style="color: #F78C6C">AS</span><span style="color: #BABED8"> ol</span></span>
<span class="line"><span style="color: #BABED8">    </span><span style="color: #F78C6C">WHERE</span><span style="color: #BABED8">   ol.CustomerID </span><span style="color: #89DDFF">=</span><span style="color: #BABED8"> @CustomerID</span></span>
<span class="line"><span style="color: #BABED8">    </span><span style="color: #F78C6C">ORDER BY</span><span style="color: #BABED8"> ol.UnitPrice </span><span style="color: #F78C6C">DESC</span><span style="color: #BABED8">, ol.Description;</span></span>
<span class="line"><span style="color: #F78C6C">END</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">The test is simple by design. One equality predicate against a skewed column. One sort operation where no index can fully support it. Those two things are enough to reproduce the behavior we want to analyze.</p>



<h2 class="wp-block-heading">Failure mode one: sniff small, run big</h2>



<p class="wp-block-paragraph">Compile the procedure for the minnow. Then call it for the whale.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#292d3e"><span style="background:#aaafcf;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#292d3e">SQL</span></span><span role="button" tabindex="0" style="color:#babed8;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>EXEC sys.sp_recompile N'Demo.usp_CustomerLinesByPrice';
EXEC Demo.usp_CustomerLinesByPrice @CustomerID = @Minnow;  -- compiles here
EXEC Demo.usp_CustomerLinesByPrice @CustomerID = @Whale;   -- suffers here
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki material-theme-palenight" style="background-color: #292D3E" tabindex="0"><code><span class="line"><span style="color: #F78C6C">EXEC</span><span style="color: #BABED8"> sys.sp_recompile </span><span style="color: #C3E88D">N</span><span style="color: #89DDFF">&#39;</span><span style="color: #C3E88D">Demo.usp_CustomerLinesByPrice</span><span style="color: #89DDFF">&#39;</span><span style="color: #BABED8">;</span></span>
<span class="line"><span style="color: #F78C6C">EXEC</span><span style="color: #BABED8"> Demo.usp_CustomerLinesByPrice @CustomerID </span><span style="color: #89DDFF">=</span><span style="color: #BABED8"> @Minnow;  </span><span style="color: #676E95; font-style: italic">-- compiles here</span></span>
<span class="line"><span style="color: #F78C6C">EXEC</span><span style="color: #BABED8"> Demo.usp_CustomerLinesByPrice @CustomerID </span><span style="color: #89DDFF">=</span><span style="color: #BABED8"> @Whale;   </span><span style="color: #676E95; font-style: italic">-- suffers here</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">The plan compiled for the minnow is a good plan for the minnow: seek the non-clustered index, look up the handful of matching rows in the clustered index, sort them in a memory grant barely above the minimum. For a few hundred rows that&#8217;s exactly right.</p>



<p class="wp-block-paragraph">Then the whale arrives, and the same plan does it 500000 times.</p>



<p class="wp-block-paragraph">Two separate things have now gone wrong, and from here on I&#8217;m going to insist on naming them separately.</p>



<p class="wp-block-paragraph"><strong>The plan shape is wrong.</strong>&nbsp;Key lookups are fine in the hundreds and catastrophic in the hundreds of thousands. The logical read count tells the story: 1519167 reads to return 500000 rows. A clustered index scan would have read the table roughly once.</p>



<p class="wp-block-paragraph"><strong>The memory grant is wrong</strong>, and this is the part people find surprising. The grant is not recalculated per execution. It is&nbsp;<em>baked into the cached plan</em>&nbsp;at compile time, computed from the estimated row count and the estimated row width. Runtime reality does not get a vote. So the sort gets a grant sized for the minnow — 1 MB — while the engine&#8217;s own after-the-fact assessment of what it should have had is 0.53 MB.</p>



<p class="wp-block-paragraph">When a sort doesn&#8217;t have enough memory, it spills to tempdb. Not a warning, not a retry — it writes sort runs to disk and merges them, and your query goes from memory-speed to disk-speed while holding its locks the whole time. In the actual execution plan you&#8217;ll see a warning triangle on the Sort operator. In the Extended Events output you&#8217;ll see&nbsp;<code>sort_warning</code>&nbsp;fire.</p>



<p class="wp-block-paragraph">The gap between&nbsp;<code>GrantMB</code>&nbsp;and&nbsp;<code>IdealMB</code>&nbsp;is the fingerprint. Learn to read it.</p>



<h2 class="wp-block-heading">Failure mode two: sniff big, run small</h2>



<p class="wp-block-paragraph">Now the mirror image, which most write-ups skip, and which is the more interesting half.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#292d3e"><span style="background:#aaafcf;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#292d3e">SQL</span></span><span role="button" tabindex="0" style="color:#babed8;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>EXEC sys.sp_recompile N'Demo.usp_CustomerLinesByPrice';
EXEC Demo.usp_CustomerLinesByPrice @CustomerID = @Whale;   -- compiles here
EXEC Demo.usp_CustomerLinesByPrice @CustomerID = @Minnow;  -- wastes memory here
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki material-theme-palenight" style="background-color: #292D3E" tabindex="0"><code><span class="line"><span style="color: #F78C6C">EXEC</span><span style="color: #BABED8"> sys.sp_recompile </span><span style="color: #C3E88D">N</span><span style="color: #89DDFF">&#39;</span><span style="color: #C3E88D">Demo.usp_CustomerLinesByPrice</span><span style="color: #89DDFF">&#39;</span><span style="color: #BABED8">;</span></span>
<span class="line"><span style="color: #F78C6C">EXEC</span><span style="color: #BABED8"> Demo.usp_CustomerLinesByPrice @CustomerID </span><span style="color: #89DDFF">=</span><span style="color: #BABED8"> @Whale;   </span><span style="color: #676E95; font-style: italic">-- compiles here</span></span>
<span class="line"><span style="color: #F78C6C">EXEC</span><span style="color: #BABED8"> Demo.usp_CustomerLinesByPrice @CustomerID </span><span style="color: #89DDFF">=</span><span style="color: #BABED8"> @Minnow;  </span><span style="color: #676E95; font-style: italic">-- wastes memory here</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">The plan compiled for the whale is a clustered index scan with a memory grant sized for half a million wide rows. Reused for the minnow, it returns a few hundred rows and finishes quickly.</p>



<p class="wp-block-paragraph">Nothing spills. Nothing is slow. This query will never appear in your &#8220;top ten by duration&#8221; report. It is not broken in any way a duration-based monitor can see.</p>



<p class="wp-block-paragraph">It is, however,&nbsp;<strong>greedy</strong>. It asked for 127.31 MB of workspace memory and touched 0.22 MB of it.</p>



<p class="wp-block-paragraph">Here&#8217;s why you should care about memory a query didn&#8217;t use:</p>



<ul class="wp-block-list">
<li>A memory grant is&nbsp;<em>reserved</em>&nbsp;for the lifetime of the query, used or not. It is not lazily allocated and it is not shared.</li>



<li>Workspace memory is a finite, instance-wide pool. There is only so much of it.</li>



<li>When the pool is exhausted, incoming queries queue on&nbsp;<code>RESOURCE_SEMAPHORE</code>&nbsp;waits — they sit there, having compiled successfully, waiting for permission to start.</li>
</ul>



<p class="wp-block-paragraph">So one procedure with a badly sniffed grant, called from enough sessions concurrently, will stall queries that have nothing to do with it. The victim is never the culprit. That&#8217;s what makes this one hard to trace back, and it&#8217;s why duration is a bad detector for half of all parameter sniffing problems.</p>



<p class="wp-block-paragraph">The detector that does work is a comparison, not a threshold:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#292d3e"><span style="background:#aaafcf;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#292d3e">SQL</span></span><span role="button" tabindex="0" style="color:#babed8;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>SELECT  qs.execution_count,
        GrantMB = qs.last_grant_kb      / 1024.0,
        UsedMB  = qs.last_used_grant_kb / 1024.0,
        IdealMB = qs.last_ideal_grant_kb/ 1024.0,
        st.text
FROM    sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
WHERE   qs.last_grant_kb > 1024
  AND   qs.last_grant_kb > qs.last_used_grant_kb * 2
ORDER BY qs.last_grant_kb DESC;
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki material-theme-palenight" style="background-color: #292D3E" tabindex="0"><code><span class="line"><span style="color: #F78C6C">SELECT</span><span style="color: #BABED8">  qs.execution_count,</span></span>
<span class="line"><span style="color: #BABED8">        GrantMB </span><span style="color: #89DDFF">=</span><span style="color: #BABED8"> qs.last_grant_kb      </span><span style="color: #89DDFF">/</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">1024</span><span style="color: #BABED8">.</span><span style="color: #F78C6C">0</span><span style="color: #BABED8">,</span></span>
<span class="line"><span style="color: #BABED8">        UsedMB  </span><span style="color: #89DDFF">=</span><span style="color: #BABED8"> qs.last_used_grant_kb </span><span style="color: #89DDFF">/</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">1024</span><span style="color: #BABED8">.</span><span style="color: #F78C6C">0</span><span style="color: #BABED8">,</span></span>
<span class="line"><span style="color: #BABED8">        IdealMB </span><span style="color: #89DDFF">=</span><span style="color: #BABED8"> qs.last_ideal_grant_kb</span><span style="color: #89DDFF">/</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">1024</span><span style="color: #BABED8">.</span><span style="color: #F78C6C">0</span><span style="color: #BABED8">,</span></span>
<span class="line"><span style="color: #BABED8">        st.text</span></span>
<span class="line"><span style="color: #F78C6C">FROM</span><span style="color: #BABED8">    sys.dm_exec_query_stats </span><span style="color: #F78C6C">AS</span><span style="color: #BABED8"> qs</span></span>
<span class="line"><span style="color: #F78C6C">CROSS</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">APPLY</span><span style="color: #BABED8"> sys.dm_exec_sql_text(qs.sql_handle) </span><span style="color: #F78C6C">AS</span><span style="color: #BABED8"> st</span></span>
<span class="line"><span style="color: #F78C6C">WHERE</span><span style="color: #BABED8">   qs.last_grant_kb </span><span style="color: #89DDFF">&gt;</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">1024</span></span>
<span class="line"><span style="color: #BABED8">  </span><span style="color: #F78C6C">AND</span><span style="color: #BABED8">   qs.last_grant_kb </span><span style="color: #89DDFF">&gt;</span><span style="color: #BABED8"> qs.last_used_grant_kb </span><span style="color: #89DDFF">*</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">2</span></span>
<span class="line"><span style="color: #F78C6C">ORDER BY</span><span style="color: #BABED8"> qs.last_grant_kb </span><span style="color: #F78C6C">DESC</span><span style="color: #BABED8">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Granted far above used means memory reserved and wasted. Ideal far above granted means the query spilled. Same three columns, two different diseases.</p>



<h2 class="wp-block-heading">Two problems, not one</h2>



<p class="wp-block-paragraph">This is the pivot of the whole post, so here it is in one table:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th></th><th>Wrong plan shape</th><th>Wrong memory grant</th></tr></thead><tbody><tr><td><strong>Symptom</strong></td><td>Huge logical reads, wrong operators</td><td>Spills to tempdb, or memory reserved and never touched</td></tr><tr><td><strong>Detect with</strong></td><td><code>last_logical_reads</code>, the plan itself</td><td><code>last_grant_kb</code>&nbsp;vs&nbsp;<code>last_used_grant_kb</code>&nbsp;vs&nbsp;<code>last_ideal_grant_kb</code></td></tr><tr><td><strong>Shows up in a duration report?</strong></td><td>Yes</td><td>Only half the time</td></tr><tr><td><strong><code>OPTION (RECOMPILE)</code></strong></td><td>Fixes it</td><td>Fixes it</td></tr><tr><td><strong>Memory grant feedback</strong></td><td><strong>Never fixes it</strong></td><td>Fixes it, over several executions</td></tr><tr><td><strong>PSPO (SQL Server 2022)</strong></td><td>Fixes it</td><td>Indirectly, by fixing the estimate</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">Everything below refers back to this.</p>



<h2 class="wp-block-heading"><code>OPTION (RECOMPILE)</code></h2>



<p class="wp-block-paragraph">The blunt instrument, and the one that always works.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#292d3e"><span style="background:#aaafcf;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#292d3e">SQL</span></span><span role="button" tabindex="0" style="color:#babed8;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>    ...
    ORDER BY ol.UnitPrice DESC, ol.Description
    OPTION (RECOMPILE);
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki material-theme-palenight" style="background-color: #292D3E" tabindex="0"><code><span class="line"><span style="color: #BABED8">    ...</span></span>
<span class="line"><span style="color: #BABED8">    </span><span style="color: #F78C6C">ORDER BY</span><span style="color: #BABED8"> ol.UnitPrice </span><span style="color: #F78C6C">DESC</span><span style="color: #BABED8">, ol.Description</span></span>
<span class="line"><span style="color: #BABED8">    </span><span style="color: #F78C6C">OPTION</span><span style="color: #BABED8"> (</span><span style="color: #F78C6C">RECOMPILE</span><span style="color: #BABED8">);</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Both columns of that table go green. The plan is built against the actual parameter value on every single execution, so the shape is right and the grant is right, every time, by construction. You get a bonus, too: because the value is a literal constant at compile time, the optimizer can do things it can&#8217;t do for a cached plan — fold constants, eliminate whole branches of a query, simplify predicates it would otherwise have to keep general.</p>



<p class="wp-block-paragraph">In the demo, scenario D calls the recompiling version with the minnow, then the whale, then the minnow again, and the grant tracks the actual row count in both directions: 1, 127.35, 127.34 MB.</p>



<p class="wp-block-paragraph">Now the cost, stated honestly, because &#8220;just add RECOMPILE&#8221; is bad advice delivered confidently.</p>



<p class="wp-block-paragraph"><strong>You pay a compilation on every execution.</strong>&nbsp;Compilation is CPU-expensive. On a procedure called four thousand times a minute, you have traded an intermittent memory problem for a permanent CPU problem, and the second one is harder to notice because it doesn&#8217;t spike — it just raises your floor.</p>



<p class="wp-block-paragraph"><strong>You lose the plan cache as a diagnostic surface.</strong>&nbsp;After a recompiling statement runs, there&#8217;s nothing in&nbsp;<code>sys.dm_exec_cached_plans</code>&nbsp;to look at. Your monitoring gets thinner exactly where you were having trouble.</p>



<p class="wp-block-paragraph"><strong>Statement-level, not procedure-level.</strong>&nbsp;<code>OPTION (RECOMPILE)</code>&nbsp;on one statement recompiles that statement.&nbsp;<code>CREATE PROCEDURE ... WITH RECOMPILE</code>&nbsp;recompiles every statement in the procedure on every call, including the nine that were fine. It is almost never what you want. If you inherited a procedure with&nbsp;<code>WITH RECOMPILE</code>&nbsp;in the header, that&#8217;s usually someone&#8217;s decade-old shotgun fix for a problem in one statement.</p>



<p class="wp-block-paragraph">The rule of thumb worth internalizing:&nbsp;<strong>RECOMPILE is priced per execution.</strong>&nbsp;A reporting procedure called forty times an hour should probably just use it and stop thinking about this. A hot OLTP path called forty times a second should not.</p>



<p class="wp-block-paragraph">And note something for later: after scenario D there is&nbsp;<strong>no cached plan at all</strong>. Hold that thought.</p>



<h2 class="wp-block-heading">Memory grant feedback</h2>



<p class="wp-block-paragraph">Now the feature everyone wants to talk about, and the one whose limits are routinely oversold.</p>



<p class="wp-block-paragraph">Memory grant feedback is a learning loop. After a query executes, the engine compares the memory it granted against the memory the query actually used. If the query spilled, the grant was too small — write a bigger number onto the cached plan for next time. If the grant was more than twice what was used, it was too big — write a smaller one. Over a handful of executions the grant converges on reality without anybody recompiling anything.</p>



<p class="wp-block-paragraph">What you need for it:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Feature</th><th>Version</th><th>Also requires</th></tr></thead><tbody><tr><td>Batch mode memory grant feedback</td><td>2017+</td><td>compatibility level 140</td></tr><tr><td>Row mode memory grant feedback</td><td>2019+</td><td>compatibility level 150</td></tr><tr><td>Persistence across cache eviction</td><td>2022+</td><td>Query Store enabled</td></tr><tr><td>Percentile grant feedback</td><td>2022+</td><td>compatibility level 160</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">That compatibility level column is where most people get stuck. A database restored from an older instance keeps its old compatibility level forever; WideWorldImporters ships at 130. You can be running SQL Server 2022 and getting none of this.</p>



<p class="wp-block-paragraph">Scenario C in the demo sets the loop up to succeed: compile for the minnow, then call the whale six times in a row with nothing recompiling in between. That last part matters. Feedback is written onto the cached plan, so anything that evicts the plan throws away everything the engine learned. This is also why the adjustment always lands on the&nbsp;<em>following</em>&nbsp;execution — execution&nbsp;<em>n</em>&nbsp;discovers the grant was wrong, execution&nbsp;<em>n+1</em>&nbsp;benefits.</p>



<p class="wp-block-paragraph">The trajectory:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Execution</th><th>GrantMB</th><th>UsedMB</th><th>IdealMB</th><th>State</th></tr></thead><tbody><tr><td>1 (whale)</td><td>1.50</td><td>1.50</td><td>1.5</td><td>NULL</td></tr><tr><td>2</td><td>47.31</td><td>47.31</td><td>47.31</td><td>NULL</td></tr><tr><td>3</td><td>79.80</td><td>79.80</td><td>79.80</td><td>NULL</td></tr><tr><td>4</td><td>106.81</td><td>106.81</td><td>106.81</td><td>NULL</td></tr><tr><td>5</td><td>127.37</td><td>127.37</td><td>131.02</td><td>NULL</td></tr><tr><td>6</td><td>127.36</td><td>127.36</td><td>153.65</td><td>NULL</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">That&nbsp;<code>State</code>&nbsp;column is&nbsp;<code>IsMemoryGrantFeedbackAdjusted</code>&nbsp;from the cached plan&#8217;s XML, and it&#8217;s the cleanest way to watch the loop work: it moves from&nbsp;<code>NoFirstExecution</code>&nbsp;through&nbsp;<code>YesAdjusting</code>&nbsp;to&nbsp;<code>YesStable</code>.</p>



<p class="wp-block-paragraph">Now the three caveats, which are the actual reason this section exists.</p>



<p class="wp-block-paragraph"><strong>It fixes the grant. It never fixes the plan shape.</strong>&nbsp;Look at the&nbsp;<code>PlanShape</code>&nbsp;column across all six of those executions in the demo output. It does not change. It cannot change — memory grant feedback adjusts a number attached to an existing plan; it does not trigger a recompilation and it has no opinion about operators. Those 1519167 logical reads from failure mode one are still there on execution six. The query stops spilling and gets faster. It does not get&nbsp;<em>good</em>. If you go into this expecting feedback to solve parameter sniffing, this is where you&#8217;ll be disappointed, and it won&#8217;t be the feature&#8217;s fault.</p>



<p class="wp-block-paragraph"><strong>It&#8217;s a learning loop, so somebody has to do the learning.</strong>&nbsp;The first caller always eats the bad grant. On SQL Server 2019 and earlier, so does the first caller after any cache eviction — a plan flush, memory pressure, a stats update, a failover. SQL Server 2022&#8217;s Query Store persistence exists precisely to stop throwing that lesson away, and it&#8217;s a good reason to have Query Store on.</p>



<p class="wp-block-paragraph"><strong>It gives up if you make it thrash.</strong>&nbsp;A workload that genuinely alternates between tiny and enormous will push the grant up, then down, then up again. Rather than oscillate forever, the engine notices the instability and switches feedback off for that query. There&#8217;s an Extended Event for it —&nbsp;<code>memory_grant_feedback_loop_disabled</code>. Percentile grant feedback in SQL Server 2022 is the answer to this case: instead of chasing the last execution, it sizes the grant from a percentile of recent executions, which is far more stable across a genuinely bimodal workload.</p>



<h2 class="wp-block-heading">Why RECOMPILE and memory grant feedback don&#8217;t combine</h2>



<p class="wp-block-paragraph">This falls straight out of the two sections above, and it&#8217;s the question that sent me down this path in the first place.</p>



<p class="wp-block-paragraph">Memory grant feedback writes its correction&nbsp;<strong>onto a cached plan</strong>.&nbsp;<code>OPTION (RECOMPILE)</code>&nbsp;<strong>doesn&#8217;t leave a cached plan</strong>. There is nothing for the feedback to attach to.</p>



<p class="wp-block-paragraph">You can watch this in the demo: after scenario D runs three times, query the cached plan view and you get nothing back. Compare with scenario C, where the plan is sitting right there accumulating adjustments.</p>



<p class="wp-block-paragraph">This is not a conflict you need to resolve, and it isn&#8217;t a bug. RECOMPILE already produces an accurate grant on every execution by construction — there&#8217;s nothing left for a feedback loop to improve. But it does mean the two are&nbsp;<strong>alternatives, not layers</strong>. Don&#8217;t reach for RECOMPILE while imagining that feedback is also working quietly underneath, and don&#8217;t diagnose the absence of feedback on a recompiling statement as something being broken.</p>



<h2 class="wp-block-heading">Parameter Sensitive Plan optimization</h2>



<p class="wp-block-paragraph">Which leaves the gap in that table from earlier: memory grant feedback never fixes plan shape, and RECOMPILE fixes plan shape but charges you per execution. Is there anything that fixes the shape without the compile?</p>



<p class="wp-block-paragraph">On SQL Server 2022, yes. Parameter Sensitive Plan optimization caches&nbsp;<strong>multiple plan variants</strong>&nbsp;for a single statement and dispatches between them based on the cardinality the incoming parameter implies. The minnow gets the seek-and-lookup plan, the whale gets the scan, neither one triggers a compilation, and both come out of cache.</p>



<p class="wp-block-paragraph">It&#8217;s on by default at compatibility level 160. Its limits are worth knowing: equality predicates only, at most three of them, and the column has to be skewed enough for the engine to consider it worth the trouble — PSPO is not applied to every parameterized query, only to ones where the optimizer sees a genuine sensitivity.</p>



<p class="wp-block-paragraph">The most convincing thing I can say about PSPO is not an argument, it&#8217;s a confession about the demo:&nbsp;<strong>the setup script has to turn PSPO off.</strong>&nbsp;On a 2022 instance at compatibility level 160, scenarios A and B don&#8217;t fail. The engine handles them. I had to explicitly disable the feature to show you the classic behaviour at all:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#292d3e"><span style="background:#aaafcf;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#292d3e">SQL</span></span><span role="button" tabindex="0" style="color:#babed8;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>ALTER DATABASE SCOPED CONFIGURATION
    SET PARAMETER_SENSITIVE_PLAN_OPTIMIZATION = OFF;
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki material-theme-palenight" style="background-color: #292D3E" tabindex="0"><code><span class="line"><span style="color: #F78C6C">ALTER</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">DATABASE</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">SCOPED</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">CONFIGURATION</span></span>
<span class="line"><span style="color: #BABED8">    </span><span style="color: #F78C6C">SET</span><span style="color: #BABED8"> PARAMETER_SENSITIVE_PLAN_OPTIMIZATION </span><span style="color: #89DDFF">=</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">OFF</span><span style="color: #BABED8">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Scenario E turns it back on so you can see the contrast: same procedure, same two parameters, no recompilation between them, two different plan shapes.</p>



<h2 class="wp-block-heading">Things that look like fixes</h2>



<p class="wp-block-paragraph">A tour of the mitigations you&#8217;ll find in older Stack Overflow answers, and what they actually cost.</p>



<p class="wp-block-paragraph"><strong><code>OPTIMIZE FOR UNKNOWN</code>.</strong>&nbsp;Compiles using the density vector — the average rows per distinct value — instead of the histogram. You&#8217;ve traded a plan that is excellent for most callers and terrible for a few, for a plan that is mediocre for everyone. Sometimes that really is the right trade, especially when the terrible case is bad enough to cause an outage. But it should be a decision, not a reflex.</p>



<p class="wp-block-paragraph"><strong><code>OPTIMIZE FOR (@CustomerID = 12345)</code>.</strong>&nbsp;You&#8217;ve pinned the plan to a magic constant. It works until the data distribution moves, at which point it fails silently and nobody remembers that number is in there.</p>



<p class="wp-block-paragraph"><strong>Assigning parameters to local variables.</strong>&nbsp;The folk-remedy version of&nbsp;<code>OPTIMIZE FOR UNKNOWN</code>&nbsp;— the optimizer can&#8217;t sniff a local variable, so you get the density estimate. Same trade-off, but now it&#8217;s invisible, and the next developer will &#8220;clean up&#8221; the pointless variable assignment and reintroduce the bug.</p>



<p class="wp-block-paragraph"><strong>Updating statistics, or rebuilding the index.</strong>&nbsp;This evicts plans, so the symptom goes away, so it looks like a fix. It will look like a fix again next week, and the week after, forever. This is the single most common way a parameter sniffing problem survives for years: it is permanently one maintenance job away from being invisible.</p>



<p class="wp-block-paragraph"><strong>Restarting SQL Server.</strong>&nbsp;Same mechanism, more downtime, and it usually happens at 3am while someone types &#8220;resolved&#8221; into a ticket.</p>



<p class="wp-block-paragraph"><strong>Splitting the procedure into branches</strong>&nbsp;— an&nbsp;<code>IF</code>&nbsp;that routes big customers to one procedure and small ones to another, so each gets its own plan. This one genuinely works. It also hardcodes today&#8217;s understanding of your data into control flow, and it ages badly. Reach for it when PSPO isn&#8217;t available and RECOMPILE is too expensive, and leave a comment explaining why.</p>



<h2 class="wp-block-heading">So what should you actually do?</h2>



<ol class="wp-block-list">
<li><strong>Confirm the column is skewed.</strong>&nbsp;Group by the predicate column, compare the top and bottom. Within an order of magnitude? It isn&#8217;t parameter sniffing. Go look somewhere else.</li>



<li><strong>Work out which problem you have.</strong>&nbsp;Compare&nbsp;<code>last_grant_kb</code>,&nbsp;<code>last_used_grant_kb</code>, and&nbsp;<code>last_ideal_grant_kb</code>&nbsp;against&nbsp;<code>last_logical_reads</code>. Wrong grant, wrong shape, or both.</li>



<li><strong>Grant only, on 2019 or later, with steady traffic</strong>&nbsp;— check your compatibility level is 150+ and let memory grant feedback handle it. Turn on Query Store if you&#8217;re on 2022, so the lesson survives an eviction.</li>



<li><strong>Shape wrong, on 2022</strong>&nbsp;— check whether PSPO is on before you write any code. You may not have a problem.</li>



<li><strong>Shape wrong, low call rate</strong>&nbsp;—&nbsp;<code>OPTION (RECOMPILE)</code>&nbsp;on the statement. Measure the compile cost afterwards rather than assuming it&#8217;s fine.</li>



<li><strong>Shape wrong, high call rate, no PSPO available</strong>&nbsp;— branch the procedure, and write down why in a comment, because in three years the reason will not be obvious.</li>
</ol>



<p class="wp-block-paragraph">The thing I&#8217;d most like you to take away is the second step. Almost everything written about parameter sniffing collapses the two failure modes into one story, and once you&#8217;ve separated them the modern features stop looking mysterious. Memory grant feedback isn&#8217;t under-delivering — it&#8217;s doing exactly the one job it claims to do, and PSPO is the feature that does the other one.</p>



<h2 class="wp-block-heading">Run it yourself</h2>



<p class="wp-block-paragraph">Download the sql files from my repo (see link below):</p>



<pre class="wp-block-code has-babed-8-color has-text-color has-875-rem-font-size"><code>01-setup.sql     run once, builds the skewed table and the procedure
02-demo.sql      run the whole file, all five scenarios, records its own evidence
03-cleanup.sql   restores everything it changed
</code></pre>



<p class="wp-block-paragraph">Two things before you do. Turn on&nbsp;<strong>Query Options → Results → Grid → Discard results after execution</strong>&nbsp;in SSMS, because the procedure returns half a million wide rows about ten times over and you want to be timing the server rather than the grid. And know that&nbsp;<code>01-setup.sql</code>&nbsp;raises your database compatibility level and turns PSPO off — both are recorded before they&#8217;re changed and restored by the cleanup script, but point it at a scratch instance, not production.</p>



<p class="wp-block-paragraph">The demo captures every measurement into&nbsp;<code>Demo.DemoResults</code>&nbsp;as it goes, so you don&#8217;t have to sit and read execution plans between executions. The summary at the bottom flags spills and wasted grants for you.</p>



<p class="wp-block-paragraph">Dowload the demo scripts from my <a href="https://github.com/MarlonRibunal/sqlserver-demos" target="_blank" rel="noopener nofollow" title=""><strong>github repo</strong></a>.</p>



<p class="wp-block-paragraph"></p><p>The post <a href="https://marlonribunal.com/demo-for-parameter-sniffing-and-memory-grant-feedback/">Demo for Parameter Sniffing and Memory Grant Feedback</a> first appeared on <a href="https://marlonribunal.com">SQL, Code, Coffee, Etc.</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>When Do You Reach For A #temp Table?</title>
		<link>https://marlonribunal.com/when-do-you-reach-for-a-temp-table/</link>
					<comments>https://marlonribunal.com/when-do-you-reach-for-a-temp-table/#comments</comments>
		
		<dc:creator><![CDATA[Marlon Ribunal]]></dc:creator>
		<pubDate>Tue, 11 Aug 2026 11:05:00 +0000</pubDate>
				<category><![CDATA[SQL Server]]></category>
		<guid isPermaLink="false">https://marlonribunal.com/?p=2869</guid>

					<description><![CDATA[<p>I needed to do some research because there is more to #temp tables than simply creating one and using it. As I started digging into the topic, I realized there are a lot of discussions around #temp tables and @table variables, especially around when one might be a better choice over the other. <a href="https://marlonribunal.com/when-do-you-reach-for-a-temp-table/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
<p>The post <a href="https://marlonribunal.com/when-do-you-reach-for-a-temp-table/">When Do You Reach For A #temp Table?</a> first appeared on <a href="https://marlonribunal.com">SQL, Code, Coffee, Etc.</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph"><em><strong>Disclaimer:</strong> Rather than spending time writing a test scenario from scratch, I used Claude Code to generate the test scenarios for this article. I wanted a certain behavior to demonstrate a couple of differences between #temp and @table. You can download the test scripts from my public GitHub repo (see info at the bottom of this post).</em></p>



<p class="wp-block-paragraph"><code>#temp</code> tables can be useful in so many ways. I hadn&#8217;t really given them much thought beyond using them when a situation called for it, until I saw the invitation for  <strong><a href="https://www.jefftaylor.io/post/t-sql-tuesday-201-invitation-temp-tables-friend-or-foe" target="_blank" rel="noopener nofollow" title="">T-SQL Tuesday #201 Invitation: Temp Tables, Friend or Foe?</a></strong> This month&#8217;s T-SQL Tuesday is hosted by Jeff Taylor (<a href="https://www.jefftaylor.io/profile/jeff/profile" target="_blank" rel="noopener nofollow" title=""><strong>b</strong></a>). </p>


<div class="wp-block-image">
<figure class="alignleft size-full"><a href="https://www.jefftaylor.io/post/t-sql-tuesday-201-invitation-temp-tables-friend-or-foe"><img loading="lazy" decoding="async" width="420" height="420" src="https://marlonribunal.com/wp-content/uploads/2026/08/TSQL_Tuesday_Logo.png" alt="" class="wp-image-2872" srcset="https://marlonribunal.com/wp-content/uploads/2026/08/TSQL_Tuesday_Logo.png 420w, https://marlonribunal.com/wp-content/uploads/2026/08/TSQL_Tuesday_Logo-300x300.png 300w, https://marlonribunal.com/wp-content/uploads/2026/08/TSQL_Tuesday_Logo-150x150.png 150w" sizes="auto, (max-width: 420px) 100vw, 420px" /></a></figure>
</div>


<p class="wp-block-paragraph">For this post, I needed to do some research because there is more to <code>#temp </code>tables than simply creating one and using it. As I started digging into the topic, I realized there are a lot of discussions around <code>#temp</code> tables and <code>@table</code> variables, especially around when one might be a better choice over the other.</p>



<p class="wp-block-paragraph">One of the common arguments is that <code>#temp </code>tables go to disk while <code>@table</code> variables stay in memory. Another argument is that this is a myth. That got me curious about what the actual differences are and when they really matter. Discussions like this almost always starts with where the data is stored (disk vs memory).</p>



<p class="wp-block-paragraph">Both <code>#temp </code>tables and <code>@table</code> variables <a href="https://learn.microsoft.com/en-us/sql/t-sql/data-types/table-transact-sql?view=sql-server-ver17#:~:text=Table%20variables%20are%20created%20in,in%20memory%20(data%20cache)" target="_blank" rel="noopener nofollow" title="">use <code><strong>tempdb</strong></code></a>. Both allocate pages that are managed by the <code>buffer pool</code>. Depending on the size of the data, memory availability, and other factors, those pages may or may not ever be written to disk. If that&#8217;s the case, then maybe &#8220;memory versus disk&#8221; isn&#8217;t really the question we should be asking.</p>



<p class="wp-block-paragraph">Let&#8217;s take a look at a couple of scenarios.</p>



<p class="wp-block-paragraph"><strong>Test SQL:</strong> SQL Server 2022 CU25 (16.0.4255.1) container (Orbstack on Macbook pro)<br /><strong>CPU:</strong> 8 (schedulers)<br /><strong>MAXDOP:</strong> 0 <br /><strong>Cost Threshold for Parallelism:</strong> Default 5 (for parallelism test scenario)</p>



<h2 class="wp-block-heading">The difference is statistics</h2>



<p class="wp-block-paragraph">One of the biggest differences between <code>#temp</code> tables and <code>@table</code> variables is statistics. <code>#temp</code> tables can have statistics created and maintained by SQL Server, which gives the optimizer more information when generating an execution plan. <code>@table</code> variables do not have column statistics, although newer versions of SQL Server have improved their cardinality estimates through <strong>deferred compilation</strong>.</p>



<p class="wp-block-paragraph"><code>#temp</code> tables can have statistics. Those statistics include histograms that help the optimizer understand how the data is distributed and make better estimates.</p>



<p class="wp-block-paragraph">A table variable does not get column statistics. Even with newer versions of SQL Server and improvements like deferred compilation, the optimizer still does not have the same level of information that it has with a <code>#temp</code> table.</p>



<p class="wp-block-paragraph">This is where many of the differences start to show up. Things like indexes, constraints, recompiles, and parallelism are often related to the fact that a <code>#temp</code> table is a temporary table with metadata that the optimizer can use, while a table variable has different behavior.</p>



<p class="wp-block-paragraph">The rule I am starting to use from this research is simple:</p>



<p class="wp-block-paragraph">Use a <code>#temp</code> table when the optimizer needs more information about the data. Use a table variable when the amount of data is small, the usage is simple, or you specifically need the behavior that a table variable provides.</p>



<p class="wp-block-paragraph">Let&#8217;s take a look at a simple test.</p>



<p class="wp-block-paragraph">I wanted to keep this as fair as possible. Both objects have the same structure, the same data, and the same nonclustered index. All the test scripts can be found in the Github repo (see link at the bottom of this post).</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#292d3e"><span style="background:#aaafcf;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#292d3e">SQL</span></span><span role="button" tabindex="0" style="color:#babed8;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>CREATE TABLE #temptable 
(
    id int NOT NULL, 
    grp int NOT NULL, 
    INDEX ix_grp NONCLUSTERED (grp)
);

DECLARE @tablevariable TABLE 
(
    id int NOT NULL, 
    grp int NOT NULL, 
    INDEX ix_grp NONCLUSTERED (grp)
);</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki material-theme-palenight" style="background-color: #292D3E" tabindex="0"><code><span class="line"><span style="color: #F78C6C">CREATE</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">TABLE</span><span style="color: #BABED8"> #temptable </span></span>
<span class="line"><span style="color: #BABED8">(</span></span>
<span class="line"><span style="color: #BABED8">    id </span><span style="color: #C792EA">int</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">NOT NULL</span><span style="color: #BABED8">, </span></span>
<span class="line"><span style="color: #BABED8">    grp </span><span style="color: #C792EA">int</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">NOT NULL</span><span style="color: #BABED8">, </span></span>
<span class="line"><span style="color: #BABED8">    </span><span style="color: #F78C6C">INDEX</span><span style="color: #BABED8"> ix_grp </span><span style="color: #F78C6C">NONCLUSTERED</span><span style="color: #BABED8"> (grp)</span></span>
<span class="line"><span style="color: #BABED8">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F78C6C">DECLARE</span><span style="color: #BABED8"> @tablevariable </span><span style="color: #F78C6C">TABLE</span><span style="color: #BABED8"> </span></span>
<span class="line"><span style="color: #BABED8">(</span></span>
<span class="line"><span style="color: #BABED8">    id </span><span style="color: #C792EA">int</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">NOT NULL</span><span style="color: #BABED8">, </span></span>
<span class="line"><span style="color: #BABED8">    grp </span><span style="color: #C792EA">int</span><span style="color: #BABED8"> </span><span style="color: #F78C6C">NOT NULL</span><span style="color: #BABED8">, </span></span>
<span class="line"><span style="color: #BABED8">    </span><span style="color: #F78C6C">INDEX</span><span style="color: #BABED8"> ix_grp </span><span style="color: #F78C6C">NONCLUSTERED</span><span style="color: #BABED8"> (grp)</span></span>
<span class="line"><span style="color: #BABED8">);</span></span></code></pre></div>



<p class="wp-block-paragraph">The data is intentionally skewed. <code>grp = 1</code> has 9,000 rows, while <code>grp = 2</code> has only 10 rows.</p>



<p class="wp-block-paragraph">When I checked the estimated row counts, the difference was obvious.</p>



<p class="wp-block-paragraph">The <code>#temp</code> table had statistics, so the optimizer had information about the data distribution. The estimates were close to the actual row counts.</p>



<p class="wp-block-paragraph">The table variable was different. Even though it had the same index, the optimizer did not have the same information available. The index gave it something to seek on, but it did not tell the optimizer how the data was distributed.</p>



<p class="wp-block-paragraph">That distinction matters because estimates influence the rest of the execution plan. Row estimates affect join choices, memory grants, and other optimizer decisions. If SQL Server estimates 100 rows but the query actually returns 9,000 rows, the optimizer may choose a plan that isn&#8217;t optimal for the actual workload. That can also lead to memory spills to tempdb if the memory grant is too small. </p>



<p class="wp-block-paragraph">One thing I noticed while testing this is that the estimate for a table variable is not always the same. For example, removing the index can change the estimate. The important part is that the optimizer still has limited information about the data inside a table variable.</p>



<p class="wp-block-paragraph">So what about SQL Server 2019 and <strong>table variable deferred compilation?</strong></p>



<p class="wp-block-paragraph">Deferred compilation helps because SQL Server can see the table variable row count before compiling the statement. This improves cardinality estimates in many scenarios.</p>



<p class="wp-block-paragraph">However, it does not create statistics. Knowing that a table variable has 10,000 rows is different from knowing how those 10,000 rows are distributed. A row count can help, but it does not replace a histogram.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>source</th><th>predicate</th><th>estimated</th><th>true</th></tr></thead><tbody><tr><td><code>#temp</code></td><td><code>grp = 1</code></td><td><strong>9,000</strong></td><td>9,000</td></tr><tr><td><code>#temp</code></td><td><code>grp = 2</code></td><td><strong>10</strong></td><td>10</td></tr><tr><td><code>@tablevar</code></td><td><code>grp = 1</code></td><td><strong>100</strong></td><td>9,000</td></tr><tr><td><code>@tablevar</code></td><td><code>grp = 2</code></td><td><strong>100</strong></td><td>10</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading">Table variables migh have a problem with parallelism</h2>



<p class="wp-block-paragraph"><em><strong>Note</strong>: It is quite complicated to test paralellism on my test environment. Some tests results returned &#8220;inconclusive&#8221;. Your mileage varies (depending on your config basically).</em></p>



<p class="wp-block-paragraph">I also looked at how <code>#temp</code> tables and <code>@table</code> variables behave when it comes to parallelism.</p>



<p class="wp-block-paragraph">A common statement is: &#8220;<code>@table</code> variables are always serial.&#8221; That may not be completely accurate. But again, I have not tested this extensively. FYI.</p>



<p class="wp-block-paragraph">The restriction is related to modifying the table variable, not reading from it. For example, a regular <code>SELECT</code> or a query that reads from a table variable can still use parallelism. The limitation shows up when SQL Server is inserting into or modifying the table variable. I need to test this with bigger workload when I get the chance. </p>



<p class="wp-block-paragraph">Again, this is not conclusive.</p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>statement</th><th>DOP</th></tr></thead><tbody><tr><td>control: plain&nbsp;<code>SELECT ... GROUP BY</code></td><td>8</td></tr><tr><td><code>INSERT INTO #temp ... SELECT</code></td><td>8</td></tr><tr><td><code>INSERT INTO @tablevar ... SELECT</code></td><td><strong>1</strong></td></tr><tr><td><code>SELECT</code>&nbsp;joining&nbsp;<code>@tablevar</code></td><td><strong>8</strong></td></tr></tbody></table></figure>



<p class="wp-block-paragraph">Download the test scripts to see how this looks in your environment. Link to my Github repo is at the bottom of this post.</p>



<h2 class="wp-block-heading">The impact really depends on how much data you are working with.</h2>



<p class="wp-block-paragraph">If you are inserting a small number of rows into a table variable and reading from it later, the lack of parallelism during the insert probably does not matter. The difference between a serial and parallel insert for a small dataset is not something you will likely notice.</p>



<p class="wp-block-paragraph">Where this becomes important is when you start loading a large amount of data. A table variable that is used as a staging area for thousands or millions of rows can limit the insert operation to a serial plan when a <code>#temp</code> table could take advantage of parallelism.</p>



<p class="wp-block-paragraph">For small amounts of data, use whichever option makes the code easier to understand. For larger data loads, a <code>#temp</code> table is usually worth considering.</p>



<p class="wp-block-paragraph">The test scenario used in this post covers only a couple of the differences between <code>#temp</code> tables and <code>@table</code> variables. If you want to experiment with the scenarios yourself, you can grab the test scripts from my GitHub repository and run them in your own environment.<br /></p>



<p class="wp-block-paragraph"><a href="https://github.com/MarlonRibunal/sqlserver-demos/tree/main/tempdb">https://github.com/MarlonRibunal/sqlserver-demos/tree/main/tempdb</a></p>



<div class="wp-block-comments"><h2 id="comments" class="wp-block-comments-title">One response to &#8220;When Do You Reach For A #temp Table?&#8221;</h2>

<ol class="wp-block-comment-template"><li id="comment-13397" class="pingback odd alt thread-even depth-1">

<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:40px"><div class="wp-block-avatar"></div></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow"><div class="wp-block-comment-author-name has-small-font-size"><a rel="external nofollow ugc" href="https://curatedsql.com/2026/08/13/comparing-temp-tables-to-table-variables/" target="_self" >Comparing Temp Tables to Table Variables &#8211; Curated SQL</a></div>


<div class="wp-block-group is-layout-flex wp-block-group-is-layout-flex" style="margin-top:0px;margin-bottom:0px"><div class="wp-block-comment-date has-small-font-size"><time datetime="2026-08-13T05:05:07-07:00"><a href="https://marlonribunal.com/when-do-you-reach-for-a-temp-table/comment-page-1/#comment-13397">08/13/2026</a></time></div>

</div>


<div class="wp-block-comment-content"><p>[&#8230;] Marlon Ribunal compares two techniques: [&#8230;]</p>
</div>

</div>
</div>

</li></ol>

</div><p>The post <a href="https://marlonribunal.com/when-do-you-reach-for-a-temp-table/">When Do You Reach For A #temp Table?</a> first appeared on <a href="https://marlonribunal.com">SQL, Code, Coffee, Etc.</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://marlonribunal.com/when-do-you-reach-for-a-temp-table/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>